- You got this mail because your mail address was entered at the TimeLimit App for signing in. If you did not request this mail, then you can ignore it. If you have got any questions, then you can reply to this messagge.
+ Sie erhalten diese Nachricht, da Ihre E-Mail-Adresse in der TimeLimit-App zum Anmelden eingegeben wurde. Wenn Sie diese E-Mail nicht angefordert haben, können Sie diese ignorieren. Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
- Sie erhalten diese Nachricht, da Ihre E-Mail-Adresse in der TimeLimit-App zum Anmelden eingegeben wurde. Wenn Sie diese E-Mail nicht angefordert haben, können Sie diese ignorieren. Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
+ You got this mail because your mail address was entered at the TimeLimit App for signing in. If you did not request this mail, then you can ignore it. If you have got any questions, then you can reply to this message.
© <%= mailimprint %>
diff --git a/other/mail/login/subject.ejs b/other/mail/login/subject.ejs
index f023d60..1520fa4 100644
--- a/other/mail/login/subject.ejs
+++ b/other/mail/login/subject.ejs
@@ -1 +1 @@
-<%= subject %>
+<%- subject %>
diff --git a/other/mail/login/text.ejs b/other/mail/login/text.ejs
index ffe4f81..f64a5b9 100644
--- a/other/mail/login/text.ejs
+++ b/other/mail/login/text.ejs
@@ -1,17 +1,21 @@
-<%= introtext %>
+<%- introtext %>
-<%= code %>
+<%- code %>
-<%= outrotext %>
+<%- outrotext %>
+<% if (deviceName !== null) { -%>
+<%- deviceNameIntro %> <%- deviceName %> <%- deviceNameOutro %>
+
+<% } -%>
----------------------
-You got this mail because your mail address was entered at the TimeLimit App for signing in.
-If you did not request this mail, then you can ignore it.
-If you have got any questions, then you can reply to this messagge.
-
Sie erhalten diese Nachricht, da Ihre E-Mail-Adresse in der TimeLimit-App zum Anmelden eingegeben wurde.
Wenn Sie diese E-Mail nicht angefordert haben, können Sie diese ignorieren.
Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
- <%= mailimprint %>
+You got this mail because your mail address was entered at the TimeLimit App for signing in.
+If you did not request this mail, then you can ignore it.
+If you have got any questions, then you can reply to this message.
+
+ <%- mailimprint %>
diff --git a/other/mail/manipulation/html.ejs b/other/mail/manipulation/html.ejs
index e39fa48..34a76db 100644
--- a/other/mail/manipulation/html.ejs
+++ b/other/mail/manipulation/html.ejs
@@ -2,8 +2,9 @@
-
-
+
+
+
@@ -13,18 +14,6 @@
padding: 0;
}
- .ReadMsgBody {
- width: 100%;
- }
-
- .ExternalClass {
- width: 100%;
- }
-
- .ExternalClass * {
- line-height: 100%;
- }
-
body {
margin: 0;
padding: 0;
@@ -53,29 +42,19 @@
margin: 13px 0;
}
-
-
-
+
-
+
-
-
+
+
-
-
-
+
+
+
-
-
- TimeLimit
- |
-
+
+
+
+ TimeLimit
+ |
+
+
-
+
|
|
-
-
+
+
-
-
-
+
+
+
-
-
-
- Die TimeLimit-Installation von dem Gerät
- <%= deviceName %> hat eine Manipulation gemeldet. Sie können die Details dazu in der TimeLimit-App einsehen. Solange Sie nicht die Warnung in TimeLimit bestätigen (ignorieren und/ oder beheben) erhalten Sie keine weitere Manipulationsbenachrichtigungen
- für dieses Gerät.
- TimeLimit at
- <%= deviceName %> reported a manipulation. You can see the details in the TimeLimit App. You will not get any further warnings for this device until you confirm (ignore and/ or fix) the manipulation in the TimeLimit App.
-
- |
-
+
+
+
+
+ Die TimeLimit-Installation von dem Gerät <%= deviceName %> hat eine Manipulation gemeldet. Sie können die Details dazu in der TimeLimit-App einsehen. Solange Sie nicht die Warnung in TimeLimit bestätigen (ignorieren und/ oder beheben) erhalten Sie keine weitere Manipulationsbenachrichtigungen für dieses Gerät.
+ TimeLimit at <%= deviceName %> reported a manipulation. You can see the details in the TimeLimit App. You will not get any further warnings for this device until you confirm (ignore and/ or fix) the manipulation in the TimeLimit App.
+
+ |
+
+
-
+
|
|
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
- Sie erhalten diese Nachricht, weil Sie E-Mail-Benachrichtigungen in TimeLimit aktiviert haben. Sie können die Nachrichten in der TimeLimit-App abbestellen, oder indem Sie auf diese Nachricht antworten, dass Sie diese Benachrichtigungen
- nicht mehr erhalten möchten. Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
- You got this mail because you enable mail notifications for this in TimeLimit. You can disable getting these messages in the TimeLimit App or by replying to this message that you don't want to get these notifications anymore. If
- you have got any questions, then you can reply to this messagge.
- ©
- <%= mailimprint %>
+
+
+
+
-
- |
-
+
+
+
+
|
-
+
|
-
+
+
+
+
+
+
+
+
+
+
+
+
+ Sie erhalten diese Nachricht, weil Sie E-Mail-Benachrichtigungen in TimeLimit aktiviert haben. Sie können die Nachrichten in der TimeLimit-App abbestellen. Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
+ You got this mail because you enable mail notifications for this in TimeLimit. You can disable getting these messages in the TimeLimit App. If you have got any questions, then you can reply to this message.
+ © <%= mailimprint %>
+
+ |
+
+
+
+
+
+ |
+
+
-
+
+
diff --git a/other/mail/manipulation/htmltemplate-src.txt b/other/mail/manipulation/htmltemplate-src.txt
index 586c586..a26608b 100644
--- a/other/mail/manipulation/htmltemplate-src.txt
+++ b/other/mail/manipulation/htmltemplate-src.txt
@@ -9,7 +9,7 @@
- Die TimeLimit-Installation von dem Gerät <%= deviceName %> hat eine Manipulation gemeldet.
+ Die TimeLimit-Installation von dem Gerät <%= deviceName %> hat eine Manipulation gemeldet.
Sie können die Details dazu in der TimeLimit-App einsehen.
Solange Sie nicht die Warnung in TimeLimit bestätigen (ignorieren und/ oder beheben)
@@ -17,7 +17,7 @@
- TimeLimit at <%= deviceName %> reported a manipulation.
+ TimeLimit at <%= deviceName %> reported a manipulation.
You can see the details in the TimeLimit App.
You will not get any further warnings for this device
@@ -36,15 +36,13 @@
Sie erhalten diese Nachricht, weil Sie E-Mail-Benachrichtigungen in TimeLimit aktiviert haben.
- Sie können die Nachrichten in der TimeLimit-App abbestellen, oder indem
- Sie auf diese Nachricht antworten, dass Sie diese Benachrichtigungen nicht mehr erhalten möchten.
+ Sie können die Nachrichten in der TimeLimit-App abbestellen.
Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
You got this mail because you enable mail notifications for this in TimeLimit.
- You can disable getting these messages in the TimeLimit App or by
- replying to this message that you don't want to get these notifications anymore.
- If you have got any questions, then you can reply to this messagge.
+ You can disable getting these messages in the TimeLimit App.
+ If you have got any questions, then you can reply to this message.
© <%= mailimprint %>
diff --git a/other/mail/manipulation/subject.ejs b/other/mail/manipulation/subject.ejs
index f023d60..1520fa4 100644
--- a/other/mail/manipulation/subject.ejs
+++ b/other/mail/manipulation/subject.ejs
@@ -1 +1 @@
-<%= subject %>
+<%- subject %>
diff --git a/other/mail/manipulation/text.ejs b/other/mail/manipulation/text.ejs
index 9500074..b43e637 100644
--- a/other/mail/manipulation/text.ejs
+++ b/other/mail/manipulation/text.ejs
@@ -1,11 +1,11 @@
-Die TimeLimit-Installation von dem Gerät <%= deviceName %> hat eine Manipulation gemeldet.
+Die TimeLimit-Installation von dem Gerät <%- deviceName %> hat eine Manipulation gemeldet.
Sie können die Details dazu in der TimeLimit-App einsehen.
Solange Sie nicht die Warnung in TimeLimit bestätigen (ignorieren und/ oder beheben)
erhalten Sie keine weitere Manipulationsbenachrichtigungen für dieses Gerät.
-TimeLimit at <%= deviceName %> reported a manipulation.
+TimeLimit at <%- deviceName %> reported a manipulation.
You can see the details in the TimeLimit App.
You will not get any further warnings for this device
@@ -14,13 +14,11 @@ until you confirm (ignore and/ or fix) the manipulation in the TimeLimit App.
----------------------
Sie erhalten diese Nachricht, weil Sie E-Mail-Benachrichtigungen in TimeLimit aktiviert haben.
-Sie können die Nachrichten in der TimeLimit-App abbestellen, oder indem
-Sie auf diese Nachricht antworten, dass Sie diese Benachrichtigungen nicht mehr erhalten möchten.
+Sie können die Nachrichten in der TimeLimit-App abbestellen.
Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
You got this mail because you enable mail notifications for this in TimeLimit.
-You can disable getting these messages in the TimeLimit App or by
-replying to this message that you don't want to get these notifications anymore.
-If you have got any questions, then you can reply to this messagge.
+You can disable getting these messages in the TimeLimit App.
+If you have got any questions, then you can reply to this message.
- <%= mailimprint %>
+ <%- mailimprint %>
diff --git a/other/mail/password-recovery-used/html.ejs b/other/mail/password-recovery-used/html.ejs
new file mode 100644
index 0000000..458b9da
--- /dev/null
+++ b/other/mail/password-recovery-used/html.ejs
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TimeLimit
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <%= text %>
+ <%= securityText %>
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sie erhalten diese Nachricht, da Ihr TimeLimit-Passwort geändert wurde. Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
+ You got this message because the password reset feature was used for your account. If you have got any questions, then you can reply to this message.
+ © <%= mailimprint %>
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/other/mail/password-recovery-used/htmltemplate-src.txt b/other/mail/password-recovery-used/htmltemplate-src.txt
new file mode 100644
index 0000000..8ffef9b
--- /dev/null
+++ b/other/mail/password-recovery-used/htmltemplate-src.txt
@@ -0,0 +1,39 @@
+
+
+
+
+ TimeLimit
+
+
+
+
+
+ <%= text %>
+ <%= securityText %>
+
+
+
+
+
+
+
+
+
+
+
+
+ Sie erhalten diese Nachricht, da Ihr TimeLimit-Passwort geändert wurde.
+ Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
+
+
+ You got this message because the password reset feature was used for your account.
+ If you have got any questions, then you can reply to this message.
+
+
+ © <%= mailimprint %>
+
+
+
+
+
+
diff --git a/other/mail/password-recovery-used/subject.ejs b/other/mail/password-recovery-used/subject.ejs
new file mode 100644
index 0000000..1520fa4
--- /dev/null
+++ b/other/mail/password-recovery-used/subject.ejs
@@ -0,0 +1 @@
+<%- subject %>
diff --git a/other/mail/password-recovery-used/text.ejs b/other/mail/password-recovery-used/text.ejs
new file mode 100644
index 0000000..51d46db
--- /dev/null
+++ b/other/mail/password-recovery-used/text.ejs
@@ -0,0 +1,13 @@
+<%- text %>
+
+<%- securityText %>
+
+----------------------
+
+Sie erhalten diese Nachricht, da Ihr TimeLimit-Passwort geändert wurde.
+Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
+
+You got this message because the password reset feature was used for your account.
+If you have got any questions, then you can reply to this message.
+
+ <%- mailimprint %>
diff --git a/other/mail/taskdone/html.ejs b/other/mail/taskdone/html.ejs
new file mode 100644
index 0000000..355df0b
--- /dev/null
+++ b/other/mail/taskdone/html.ejs
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TimeLimit
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <%= child %> hat angegeben, dass die Aufgabe <%= task %> erledigt wurde. Die angeblich erledigten Aufgaben werden auf der Startseite der TimeLimit-App angezeigt. Dort kann die Erledigung bestätigt werden.
+
+ Da die Anzahl der Benachrichtigungs-E-Mails begrenzt ist erhalten Sie möglicherweise nicht bei jeder Aufgabenerledigung eine derartige E-Mail.
+
+ <%= child %> reported that <%= task %> was finished. You can see the tasks which are marked as finished at the overview screen of the TimeLimit application. You can confirm the task completion there.
+
+ There are limits for the notifications mails so that it can happen that you do not get a mail for each completed task.
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sie erhalten diese Nachricht, weil Sie E-Mail-Benachrichtigungen in TimeLimit aktiviert haben. Sie können die Nachrichten in der TimeLimit-App abbestellen. Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
+ You got this mail because you enable mail notifications for this in TimeLimit. You can disable getting these messages in the TimeLimit App. If you have got any questions, then you can reply to this message.
+ © <%= mailimprint %>
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/other/mail/taskdone/htmltemplate-src.txt b/other/mail/taskdone/htmltemplate-src.txt
new file mode 100644
index 0000000..5cd64d2
--- /dev/null
+++ b/other/mail/taskdone/htmltemplate-src.txt
@@ -0,0 +1,57 @@
+
+
+
+
+ TimeLimit
+
+
+
+
+
+
+ <%= child %> hat angegeben, dass die Aufgabe <%= task %> erledigt wurde.
+ Die angeblich erledigten Aufgaben werden auf der Startseite der TimeLimit-App
+ angezeigt. Dort kann die Erledigung bestätigt werden.
+
+
+ Da die Anzahl der Benachrichtigungs-E-Mails begrenzt ist erhalten Sie
+ möglicherweise nicht bei jeder Aufgabenerledigung eine derartige E-Mail.
+
+
+ <%= child %> reported that <%= task %> was finished.
+ You can see the tasks which are marked as finished at the overview screen
+ of the TimeLimit application. You can confirm the task completion there.
+
+
+ There are limits for the notifications mails so that it can happen that
+ you do not get a mail for each completed task.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sie erhalten diese Nachricht, weil Sie E-Mail-Benachrichtigungen in TimeLimit aktiviert haben.
+ Sie können die Nachrichten in der TimeLimit-App abbestellen.
+ Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
+
+
+ You got this mail because you enable mail notifications for this in TimeLimit.
+ You can disable getting these messages in the TimeLimit App.
+ If you have got any questions, then you can reply to this message.
+
+
+ © <%= mailimprint %>
+
+
+
+
+
+
diff --git a/other/mail/taskdone/subject.ejs b/other/mail/taskdone/subject.ejs
new file mode 100644
index 0000000..356aa76
--- /dev/null
+++ b/other/mail/taskdone/subject.ejs
@@ -0,0 +1 @@
+<%- child %>/<%- task %>
diff --git a/other/mail/taskdone/text.ejs b/other/mail/taskdone/text.ejs
new file mode 100644
index 0000000..3448ecf
--- /dev/null
+++ b/other/mail/taskdone/text.ejs
@@ -0,0 +1,25 @@
+<%- child %> hat angegeben, dass die Aufgabe <%- task %> erledigt wurde.
+Die angeblich erledigten Aufgaben werden auf der Startseite der TimeLimit-App
+angezeigt. Dort kann die Erledigung bestätigt werden.
+
+Da die Anzahl der Benachrichtigungs-E-Mails begrenzt ist erhalten Sie
+möglicherweise nicht bei jeder Aufgabenerledigung eine derartige E-Mail.
+
+<%- child %> reported that <%- task %> was finished.
+You can see the tasks which are marked as finished at the overview screen
+of the TimeLimit application. You can confirm the task completion there.
+
+There are limits for the notifications mails so that it can happen that
+you do not get a mail for each completed task.
+
+----------------------
+
+Sie erhalten diese Nachricht, weil Sie E-Mail-Benachrichtigungen in TimeLimit aktiviert haben.
+Sie können die Nachrichten in der TimeLimit-App abbestellen.
+Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
+
+You got this mail because you enable mail notifications for this in TimeLimit.
+You can disable getting these messages in the TimeLimit App.
+If you have got any questions, then you can reply to this message.
+
+ <%- mailimprint %>
diff --git a/other/mail/uninstall/html.ejs b/other/mail/uninstall/html.ejs
index 1becf92..377dd43 100644
--- a/other/mail/uninstall/html.ejs
+++ b/other/mail/uninstall/html.ejs
@@ -2,8 +2,9 @@
-
-
+
+
+
@@ -42,20 +43,20 @@
}
-
-
+
-
+
-
+
-
+
-
-
- TimeLimit
- |
-
+
+
+
+ TimeLimit
+ |
+
+
-
+
|
-
+
-
+
-
-
-
- TimeLimit wurde vom Gerät
- <%= deviceName %> entfernt. Ein Zurücksetzen der App, wonach diese immer noch "da", aber nicht eingerichtet ist, zählt auch als Entfernen. In jedem Fall wurde diese Aktion durch den Benutzer des Gerätes durchgeführt - in der Voreinstellung kann
- TimeLimit jederzeit, auch durch das Kind, entfernt werden. Technisch bedingt wird nicht jede Entfernung erkannt, sodass nicht in jedem Fall diese Benachrichtigung kommt.
- TimeLimit was removed from
- <%= deviceName %>. A reset of the App, after which it is still "there", but not set up, is considered a removal, too. In any case, this was done by the user of the device. Remember that by default, it is always possible to remove TimeLimit, for
- parents and children. For technical reasons, not every removal can be detected, so that you will not always get this notifications.
-
- |
-
+
+
+
+
+ TimeLimit wurde vom Gerät <%= deviceName %> entfernt. Ein Zurücksetzen der App, wonach diese immer noch "da", aber nicht eingerichtet ist, zählt auch als Entfernen. In jedem Fall wurde diese Aktion durch den Benutzer des Gerätes durchgeführt - in der Voreinstellung kann TimeLimit jederzeit, auch durch das Kind, entfernt werden. Technisch bedingt wird nicht jede Entfernung erkannt, sodass nicht in jedem Fall diese Benachrichtigung kommt.
+ TimeLimit was removed from <%= deviceName %>. A reset of the App, after which it is still "there", but not set up, is considered a removal, too. In any case, this was done by the user of the device. Remember that by default, it is always possible to remove TimeLimit, for parents and children. For technical reasons, not every removal can be detected, so that you will not always get this notifications.
+
+ |
+
+
-
+
|
-
+
-
-
-
-
-
-
-
-
-
-
-
-
- Sie erhalten diese Nachricht, weil Sie E-Mail-Benachrichtigungen in TimeLimit aktiviert haben. Sie können die Nachrichten in der TimeLimit-App abbestellen, oder indem Sie auf diese Nachricht antworten, dass Sie diese Benachrichtigungen
- nicht mehr erhalten möchten. Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
- You got this mail because you enable mail notifications for this in TimeLimit. You can disable getting these messages in the TimeLimit App or by replying to this message that you don't want to get these notifications anymore. If
- you have got any questions, then you can reply to this messagge.
- ©
- <%= mailimprint %>
+
+
+
+
-
- |
-
+
+
+
+
|
-
+
|
-
+
+
+
+
+
+
+
+
+
+
+
+
+ Sie erhalten diese Nachricht, weil Sie E-Mail-Benachrichtigungen in TimeLimit aktiviert haben. Sie können die Nachrichten in der TimeLimit-App abbestellen. Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
+ You got this mail because you enable mail notifications for this in TimeLimit. You can disable getting these messages in the TimeLimit App. If you have got any questions, then you can reply to this message.
+ © <%= mailimprint %>
+
+ |
+
+
+
+
+
+ |
+
+
-
+
+
diff --git a/other/mail/uninstall/htmltemplate-src.txt b/other/mail/uninstall/htmltemplate-src.txt
index 55a8828..b71924f 100644
--- a/other/mail/uninstall/htmltemplate-src.txt
+++ b/other/mail/uninstall/htmltemplate-src.txt
@@ -9,7 +9,7 @@
- TimeLimit wurde vom Gerät <%= deviceName %> entfernt. Ein Zurücksetzen der
+ TimeLimit wurde vom Gerät <%= deviceName %> entfernt. Ein Zurücksetzen der
App, wonach diese immer noch "da", aber nicht eingerichtet ist, zählt auch als Entfernen.
In jedem Fall wurde diese Aktion durch den Benutzer des Gerätes durchgeführt -
in der Voreinstellung kann TimeLimit jederzeit, auch durch das Kind, entfernt werden.
@@ -18,7 +18,7 @@
- TimeLimit was removed from <%= deviceName %>. A reset of the App, after which it is
+ TimeLimit was removed from <%= deviceName %>. A reset of the App, after which it is
still "there", but not set up, is considered a removal, too. In any case, this was
done by the user of the device. Remember that by default, it is always possible
to remove TimeLimit, for parents and children. For technical reasons, not every
@@ -37,15 +37,13 @@
Sie erhalten diese Nachricht, weil Sie E-Mail-Benachrichtigungen in TimeLimit aktiviert haben.
- Sie können die Nachrichten in der TimeLimit-App abbestellen, oder indem
- Sie auf diese Nachricht antworten, dass Sie diese Benachrichtigungen nicht mehr erhalten möchten.
+ Sie können die Nachrichten in der TimeLimit-App abbestellen.
Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
You got this mail because you enable mail notifications for this in TimeLimit.
- You can disable getting these messages in the TimeLimit App or by
- replying to this message that you don't want to get these notifications anymore.
- If you have got any questions, then you can reply to this messagge.
+ You can disable getting these messages in the TimeLimit App.
+ If you have got any questions, then you can reply to this message.
© <%= mailimprint %>
diff --git a/other/mail/uninstall/subject.ejs b/other/mail/uninstall/subject.ejs
index f023d60..1520fa4 100644
--- a/other/mail/uninstall/subject.ejs
+++ b/other/mail/uninstall/subject.ejs
@@ -1 +1 @@
-<%= subject %>
+<%- subject %>
diff --git a/other/mail/uninstall/text.ejs b/other/mail/uninstall/text.ejs
index 3175096..5ac07d1 100644
--- a/other/mail/uninstall/text.ejs
+++ b/other/mail/uninstall/text.ejs
@@ -1,11 +1,11 @@
-TimeLimit wurde vom Gerät <%= deviceName %> entfernt. Ein Zurücksetzen der
+TimeLimit wurde vom Gerät <%- deviceName %> entfernt. Ein Zurücksetzen der
App, wonach diese immer noch "da", aber nicht eingerichtet ist, zählt auch als Entfernen.
In jedem Fall wurde diese Aktion durch den Benutzer des Gerätes durchgeführt -
in der Voreinstellung kann TimeLimit jederzeit, auch durch das Kind, entfernt werden.
Technisch bedingt wird nicht jede Entfernung erkannt, sodass nicht in jedem Fall diese
Benachrichtigung kommt.
-TimeLimit was removed from <%= deviceName %>. A reset of the App, after which it is
+TimeLimit was removed from <%- deviceName %>. A reset of the App, after which it is
still "there", but not set up, is considered a removal, too. In any case, this was
done by the user of the device. Remember that by default, it is always possible
to remove TimeLimit, for parents and children. For technical reasons, not every
@@ -14,13 +14,11 @@ removal can be detected, so that you will not always get this notifications.
----------------------
Sie erhalten diese Nachricht, weil Sie E-Mail-Benachrichtigungen in TimeLimit aktiviert haben.
-Sie können die Nachrichten in der TimeLimit-App abbestellen, oder indem
-Sie auf diese Nachricht antworten, dass Sie diese Benachrichtigungen nicht mehr erhalten möchten.
+Sie können die Nachrichten in der TimeLimit-App abbestellen.
Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten.
You got this mail because you enable mail notifications for this in TimeLimit.
-You can disable getting these messages in the TimeLimit App or by
-replying to this message that you don't want to get these notifications anymore.
-If you have got any questions, then you can reply to this messagge.
+You can disable getting these messages in the TimeLimit App.
+If you have got any questions, then you can reply to this message.
- <%= mailimprint %>
+ <%- mailimprint %>
diff --git a/package-lock.json b/package-lock.json
index f5755bc..879ccea 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,209 +1,6147 @@
{
"name": "timelimit-server-2018",
"version": "0.0.0",
- "lockfileVersion": 1,
+ "lockfileVersion": 2,
"requires": true,
- "dependencies": {
- "@adobe/helix-log": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/@adobe/helix-log/-/helix-log-4.5.1.tgz",
- "integrity": "sha512-9++ZtL++VDDDCxUvjNaejMwTJg7OqGVfocDrYVIbRiR3gVEs6jqfgyd9bAI8aEBi+8edj0OPnUn7j8eBQKZ/Jw==",
- "dev": true,
- "requires": {
- "big.js": "5.2.2",
- "colorette": "1.1.0",
- "ferrum": "1.7.0",
- "phin": "3.4.1",
- "polka": "0.5.2",
- "triple-beam": "1.3.0",
- "uuid": "7.0.3",
- "winston-transport": "4.3.0"
- },
+ "packages": {
+ "": {
+ "name": "timelimit-server-2018",
+ "version": "0.0.0",
+ "license": "AGPL-3.0",
"dependencies": {
- "uuid": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
- "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
- "dev": true
+ "ajv": "^7.0.2",
+ "basic-auth": "^2.0.1",
+ "body-parser": "^1.19.0",
+ "ejs": "^3.1.5",
+ "email-addresses": "^3.1.0",
+ "express": "^4.17.1",
+ "http-errors": "^1.8.0",
+ "jose": "^4.9.3",
+ "lodash": "^4.17.21",
+ "mariadb": "^2.5.2",
+ "nodemailer": "^6.7.2",
+ "pg": "^8.5.1",
+ "pg-hstore": "^2.3.3",
+ "rate-limiter-flexible": "^2.1.15",
+ "sequelize": "^6.25.5",
+ "socket.io": "^4.0.1",
+ "umzug": "^3.8.1"
+ },
+ "devDependencies": {
+ "@adobe/jsonschema2md": "^7.0.0",
+ "@types/basic-auth": "^1.1.3",
+ "@types/body-parser": "^1.19.0",
+ "@types/ejs": "^3.1.0",
+ "@types/express": "^4.17.9",
+ "@types/http-errors": "^1.8.0",
+ "@types/lodash": "^4.14.166",
+ "@types/node": "^16.11.59",
+ "@types/nodemailer": "^6.4.4",
+ "@typescript-eslint/eslint-plugin": "^7.18.0",
+ "@typescript-eslint/parser": "^7.18.0",
+ "eslint": "^8.7.0",
+ "rimraf": "^3.0.2",
+ "typescript": "^5.5.4",
+ "typescript-json-schema": "^0.52.0"
+ },
+ "optionalDependencies": {
+ "sqlite3": "^5.0.0"
+ }
+ },
+ "node_modules/@aashutoshrathi/word-wrap": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
+ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@adobe/helix-log": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@adobe/helix-log/-/helix-log-6.0.0.tgz",
+ "integrity": "sha512-+9gpf49sFDmZLV3gtjY+RmEUistqYJdVWpiqlRYpxE59x5bHFzYf93dZ7fljSTBtZdVq8lm97HxrTUloh5HvRg==",
+ "dev": true,
+ "dependencies": {
+ "big.js": "^6.1.1",
+ "colorette": "^2.0.2",
+ "ferrum": "^1.9.3",
+ "phin": "^3.6.0",
+ "polka": "^0.5.2"
+ }
+ },
+ "node_modules/@adobe/jsonschema2md": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@adobe/jsonschema2md/-/jsonschema2md-7.0.0.tgz",
+ "integrity": "sha512-kmAtrV8ljQcmPiPadMG6a/8XorXsZKP8LQKdkKSeaGb91E+hXO1/lfxa8+s1gAtnwJi2MwzmFl4/TjcCkkxesw==",
+ "dev": true,
+ "dependencies": {
+ "@adobe/helix-log": "6.0.0",
+ "@types/json-schema": "^7.0.8",
+ "@types/mdast": "^3.0.4",
+ "es2015-i18n-tag": "1.6.1",
+ "ferrum": "1.9.4",
+ "fs-extra": "10.0.0",
+ "github-slugger": "1.4.0",
+ "js-yaml": "4.1.0",
+ "json-schema": "^0.4.0",
+ "mdast-builder": "1.1.1",
+ "mdast-util-to-string": "3.1.0",
+ "readdirp": "3.6.0",
+ "remark-gfm": "^3.0.0",
+ "remark-parse": "10.0.1",
+ "remark-stringify": "10.0.2",
+ "unified": "10.1.1",
+ "unist-util-inspect": "7.0.0",
+ "yargs": "17.3.1"
+ },
+ "bin": {
+ "jsonschema2md": "cli.js"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/@arr/every": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@arr/every/-/every-1.0.1.tgz",
+ "integrity": "sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@cspotcode/source-map-consumer": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
+ "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
+ "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
+ "dev": true,
+ "dependencies": {
+ "@cspotcode/source-map-consumer": "0.8.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+ "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.11.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz",
+ "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==",
+ "dev": true,
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.6.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.57.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
+ "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@gar/promisify": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
+ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==",
+ "optional": true
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.14",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
+ "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
+ "deprecated": "Use @eslint/config-array instead",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^2.0.2",
+ "debug": "^4.3.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+ "deprecated": "Use @eslint/object-schema instead",
+ "dev": true
+ },
+ "node_modules/@mapbox/node-pre-gyp": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz",
+ "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==",
+ "optional": true,
+ "dependencies": {
+ "detect-libc": "^2.0.0",
+ "https-proxy-agent": "^5.0.0",
+ "make-dir": "^3.1.0",
+ "node-fetch": "^2.6.7",
+ "nopt": "^5.0.0",
+ "npmlog": "^5.0.1",
+ "rimraf": "^3.0.2",
+ "semver": "^7.3.5",
+ "tar": "^6.1.11"
+ },
+ "bin": {
+ "node-pre-gyp": "bin/node-pre-gyp"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@npmcli/fs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz",
+ "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==",
+ "optional": true,
+ "dependencies": {
+ "@gar/promisify": "^1.0.1",
+ "semver": "^7.3.5"
+ }
+ },
+ "node_modules/@npmcli/move-file": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
+ "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==",
+ "deprecated": "This functionality has been moved to @npmcli/fs",
+ "optional": true,
+ "dependencies": {
+ "mkdirp": "^1.0.4",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@polka/url": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz",
+ "integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==",
+ "dev": true
+ },
+ "node_modules/@rushstack/node-core-library": {
+ "version": "5.5.1",
+ "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.5.1.tgz",
+ "integrity": "sha512-ZutW56qIzH8xIOlfyaLQJFx+8IBqdbVCZdnj+XT1MorQ1JqqxHse8vbCpEM+2MjsrqcbxcgDIbfggB1ZSQ2A3g==",
+ "dependencies": {
+ "ajv": "~8.13.0",
+ "ajv-draft-04": "~1.0.0",
+ "ajv-formats": "~3.0.1",
+ "fs-extra": "~7.0.1",
+ "import-lazy": "~4.0.0",
+ "jju": "~1.4.0",
+ "resolve": "~1.22.1",
+ "semver": "~7.5.4"
+ },
+ "peerDependencies": {
+ "@types/node": "*"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
}
}
},
- "@adobe/jsonschema2md": {
+ "node_modules/@rushstack/node-core-library/node_modules/ajv": {
+ "version": "8.13.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz",
+ "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.4.1"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@rushstack/node-core-library/node_modules/ajv-draft-04": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz",
+ "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==",
+ "peerDependencies": {
+ "ajv": "^8.5.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rushstack/node-core-library/node_modules/fs-extra": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
+ "dependencies": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/@rushstack/node-core-library/node_modules/jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/@rushstack/node-core-library/node_modules/universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/@rushstack/terminal": {
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.13.3.tgz",
+ "integrity": "sha512-fc3zjXOw8E0pXS5t9vTiIPx9gHA0fIdTXsu9mT4WbH+P3mYvnrX0iAQ5a6NvyK1+CqYWBTw/wVNx7SDJkI+WYQ==",
+ "dependencies": {
+ "@rushstack/node-core-library": "5.5.1",
+ "supports-color": "~8.1.1"
+ },
+ "peerDependencies": {
+ "@types/node": "*"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rushstack/terminal/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/@rushstack/ts-command-line": {
+ "version": "4.22.3",
+ "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.22.3.tgz",
+ "integrity": "sha512-edMpWB3QhFFZ4KtSzS8WNjBgR4PXPPOVrOHMbb7kNpmQ1UFS9HdVtjCXg1H5fG+xYAbeE+TMPcVPUyX2p84STA==",
+ "dependencies": {
+ "@rushstack/terminal": "0.13.3",
+ "@types/argparse": "1.0.38",
+ "argparse": "~1.0.9",
+ "string-argv": "~0.3.1"
+ }
+ },
+ "node_modules/@rushstack/ts-command-line/node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/@rushstack/ts-command-line/node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
+ },
+ "node_modules/@socket.io/component-emitter": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
+ "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
+ },
+ "node_modules/@tootallnate/once": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+ "optional": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
+ "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
+ "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
+ "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
+ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
+ "dev": true
+ },
+ "node_modules/@types/argparse": {
+ "version": "1.0.38",
+ "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz",
+ "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA=="
+ },
+ "node_modules/@types/basic-auth": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@types/basic-auth/-/basic-auth-1.1.3.tgz",
+ "integrity": "sha512-W3rv6J0IGlxqgE2eQ2pTb0gBjaGtejQpJ6uaCjz3UQ65+TFTPC5/lAE+POfx1YLdjtxvejJzsIAfd3MxWiVmfg==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/body-parser": {
+ "version": "1.19.2",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
+ "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
+ "dev": true,
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.35",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
+ "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/cookie": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
+ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
+ },
+ "node_modules/@types/cors": {
+ "version": "2.8.17",
+ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
+ "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/debug": {
+ "version": "4.1.7",
+ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz",
+ "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==",
+ "dependencies": {
+ "@types/ms": "*"
+ }
+ },
+ "node_modules/@types/ejs": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.0.tgz",
+ "integrity": "sha512-DCg+Ka+uDQ31lJ/UtEXVlaeV3d6t81gifaVWKJy4MYVVgvJttyX/viREy+If7fz+tK/gVxTGMtyrFPnm4gjrVA==",
+ "dev": true
+ },
+ "node_modules/@types/express": {
+ "version": "4.17.13",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
+ "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
+ "dev": true,
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^4.17.18",
+ "@types/qs": "*",
+ "@types/serve-static": "*"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "4.17.28",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
+ "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*"
+ }
+ },
+ "node_modules/@types/geojson": {
+ "version": "7946.0.8",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz",
+ "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA=="
+ },
+ "node_modules/@types/http-errors": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.2.tgz",
+ "integrity": "sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w==",
+ "dev": true
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.9",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
+ "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
+ "dev": true
+ },
+ "node_modules/@types/lodash": {
+ "version": "4.14.178",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz",
+ "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==",
+ "dev": true
+ },
+ "node_modules/@types/mdast": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz",
+ "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==",
+ "dev": true,
+ "dependencies": {
+ "@types/unist": "*"
+ }
+ },
+ "node_modules/@types/mime": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
+ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
+ "dev": true
+ },
+ "node_modules/@types/ms": {
+ "version": "0.7.31",
+ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz",
+ "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA=="
+ },
+ "node_modules/@types/node": {
+ "version": "16.11.59",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.59.tgz",
+ "integrity": "sha512-6u+36Dj3aDzhfBVUf/mfmc92OEdzQ2kx2jcXGdigfl70E/neV21ZHE6UCz4MDzTRcVqGAM27fk+DLXvyDsn3Jw=="
+ },
+ "node_modules/@types/nodemailer": {
+ "version": "6.4.4",
+ "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.4.tgz",
+ "integrity": "sha512-Ksw4t7iliXeYGvIQcSIgWQ5BLuC/mljIEbjf615svhZL10PE9t+ei8O9gDaD3FPCasUJn9KTLwz2JFJyiiyuqw==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/qs": {
+ "version": "6.9.7",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
+ "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
+ "dev": true
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
+ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
+ "dev": true
+ },
+ "node_modules/@types/serve-static": {
+ "version": "1.13.10",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz",
+ "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/unist": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
+ "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
+ "dev": true
+ },
+ "node_modules/@types/validator": {
+ "version": "13.7.1",
+ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.1.tgz",
+ "integrity": "sha512-I6OUIZ5cYRk5lp14xSOAiXjWrfVoMZVjDuevBYgQDYzZIjsf2CAISpEcXOkFAtpAHbmWIDLcZObejqny/9xq5Q=="
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz",
+ "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "7.18.0",
+ "@typescript-eslint/type-utils": "7.18.0",
+ "@typescript-eslint/utils": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.3.1",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^1.3.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^7.0.0",
+ "eslint": "^8.56.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz",
+ "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "7.18.0",
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/typescript-estree": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.56.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz",
+ "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz",
+ "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "7.18.0",
+ "@typescript-eslint/utils": "7.18.0",
+ "debug": "^4.3.4",
+ "ts-api-utils": "^1.3.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.56.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz",
+ "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==",
+ "dev": true,
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz",
+ "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "ts-api-utils": "^1.3.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz",
+ "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "@typescript-eslint/scope-manager": "7.18.0",
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/typescript-estree": "7.18.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.56.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz",
+ "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "7.18.0",
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
+ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
+ "dev": true
+ },
+ "node_modules/abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "optional": true
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.12.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
+ "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "optional": true,
+ "dependencies": {
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/agentkeepalive": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz",
+ "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==",
+ "optional": true,
+ "dependencies": {
+ "debug": "^4.1.0",
+ "depd": "^2.0.0",
+ "humanize-ms": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
+ "node_modules/agentkeepalive/node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "optional": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "optional": true,
+ "dependencies": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "7.2.4",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.4.tgz",
+ "integrity": "sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
+ "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv-formats/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "devOptional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/aproba": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
+ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==",
+ "optional": true
+ },
+ "node_modules/are-we-there-yet": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
+ "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
+ "optional": true,
+ "dependencies": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
+ "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g=="
+ },
+ "node_modules/bail": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
+ "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
+ "dev": true,
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/base64id": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
+ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
+ "engines": {
+ "node": "^4.5.0 || >= 5.9"
+ }
+ },
+ "node_modules/basic-auth": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+ "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+ "dependencies": {
+ "safe-buffer": "5.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/big.js": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.1.1.tgz",
+ "integrity": "sha512-1vObw81a8ylZO5ePrtMay0n018TcftpTA5HFKDaSuiUDBo8biRBtjIobw60OpwuvrGk+FsxKamqN4cnmj/eXdg==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/bigjs"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+ "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.5",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.13.0",
+ "raw-body": "2.5.2",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/body-parser/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/body-parser/node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/body-parser/node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/body-parser/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "node_modules/body-parser/node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/buffer-writer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
+ "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/cacache": {
+ "version": "15.3.0",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz",
+ "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==",
+ "optional": true,
+ "dependencies": {
+ "@npmcli/fs": "^1.0.0",
+ "@npmcli/move-file": "^1.0.1",
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "glob": "^7.1.4",
+ "infer-owner": "^1.0.4",
+ "lru-cache": "^6.0.0",
+ "minipass": "^3.1.1",
+ "minipass-collect": "^1.0.2",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.2",
+ "mkdirp": "^1.0.3",
+ "p-map": "^4.0.0",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^3.0.2",
+ "ssri": "^8.0.1",
+ "tar": "^6.0.2",
+ "unique-filename": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ccount": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
+ "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==",
+ "dev": true,
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/centra": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz",
+ "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==",
+ "dev": true,
+ "dependencies": {
+ "follow-redirects": "^1.15.6"
+ }
+ },
+ "node_modules/chalk": {
"version": "4.1.2",
- "resolved": "https://registry.npmjs.org/@adobe/jsonschema2md/-/jsonschema2md-4.1.2.tgz",
- "integrity": "sha512-H7GIKeQwR5I1SjMTNgQj2RFPDW03Nl/+ORaomvuE2BlWt8TikuTLDh0a5OyR/VHQmeVlFbk1sLRZ40JAgXgoDw==",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/character-entities": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.1.tgz",
+ "integrity": "sha512-OzmutCf2Kmc+6DrFrrPS8/tDh2+DpnrfzdICHWhcVC9eOd0N1PXmQEE1a8iM4IziIAG+8tmTq3K+oo0ubH6RRQ==",
+ "dev": true,
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "optional": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "optional": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "node_modules/color-support": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+ "optional": true,
+ "bin": {
+ "color-support": "bin.js"
+ }
+ },
+ "node_modules/colorette": {
+ "version": "2.0.16",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz",
+ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==",
+ "dev": true
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "node_modules/console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
+ "optional": true
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-disposition/node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
+ "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/cuint": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz",
+ "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=",
+ "dev": true
+ },
+ "node_modules/debug": {
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+ "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decode-named-character-reference": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.1.tgz",
+ "integrity": "sha512-YV/0HQHreRwKb7uBopyIkLG17jG6Sv2qUchk9qSoVJ2f+flwRsPNBO0hAnjt6mTNYUT+vw9Gy2ihXg4sUWPi2w==",
+ "dev": true,
+ "dependencies": {
+ "character-entities": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
+ "optional": true
+ },
+ "node_modules/denque": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
+ "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/dequal": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
+ "integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
+ "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/dottie": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz",
+ "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA=="
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
+ "node_modules/ejs": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
+ "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
+ "dependencies": {
+ "jake": "^10.8.5"
+ },
+ "bin": {
+ "ejs": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/email-addresses": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
+ "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg=="
+ },
+ "node_modules/emittery": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
+ "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/emittery?sponsor=1"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "devOptional": true
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/encoding": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+ "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+ "optional": true,
+ "dependencies": {
+ "iconv-lite": "^0.6.2"
+ }
+ },
+ "node_modules/encoding/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "optional": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/engine.io": {
+ "version": "6.6.2",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz",
+ "integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==",
+ "dependencies": {
+ "@types/cookie": "^0.4.1",
+ "@types/cors": "^2.8.12",
+ "@types/node": ">=10.0.0",
+ "accepts": "~1.3.4",
+ "base64id": "2.0.0",
+ "cookie": "~0.7.2",
+ "cors": "~2.8.5",
+ "debug": "~4.3.1",
+ "engine.io-parser": "~5.2.1",
+ "ws": "~8.17.1"
+ },
+ "engines": {
+ "node": ">=10.2.0"
+ }
+ },
+ "node_modules/engine.io-parser": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
+ "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/engine.io/node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "optional": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/err-code": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
+ "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
+ "optional": true
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es2015-i18n-tag": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/es2015-i18n-tag/-/es2015-i18n-tag-1.6.1.tgz",
+ "integrity": "sha512-MYoh9p+JTkgnzBh0MEBON6xUyzdmwT6wzsmmFJvZujGSXiI2kM+3XvFl6+AcIO2eeL6VWgtX9szSiDTMwDxyYA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.57.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
+ "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.57.0",
+ "@humanwhocodes/config-array": "^0.11.14",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3",
+ "strip-ansi": "^6.0.1",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/eslint/node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/espree": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.9.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+ "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.21.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+ "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.3",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.7.1",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.3.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.3",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.12",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.13.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.19.0",
+ "serve-static": "1.16.2",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/express/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/express/node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/express/node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/express/node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/express/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "node_modules/express/node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/express/node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
+ },
+ "node_modules/fast-uri": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz",
+ "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw=="
+ },
+ "node_modules/fastestsmallesttextencoderdecoder": {
+ "version": "1.0.22",
+ "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz",
+ "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==",
+ "dev": true
+ },
+ "node_modules/fastq": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
+ "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/ferrum": {
+ "version": "1.9.4",
+ "resolved": "https://registry.npmjs.org/ferrum/-/ferrum-1.9.4.tgz",
+ "integrity": "sha512-ooNerLoIht/dK4CQJux93z/hnt9JysrXniJCI3r6YRgmHeXC57EJ8XaTCT1Gm8LfhIAeWxyJA0O7d/W3pqDYRg==",
+ "dev": true,
+ "dependencies": {
+ "fastestsmallesttextencoderdecoder": "1.0.22",
+ "lodash.isplainobject": "4.0.6",
+ "xxhashjs": "0.2.2"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/filelist": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
+ "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
+ "dependencies": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+ "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/finalhandler/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/finalhandler/node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/finalhandler/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/finalhandler/node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz",
+ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==",
+ "dev": true
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.15.6",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
+ "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "devOptional": true
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gauge": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
+ "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
+ "optional": true,
+ "dependencies": {
+ "aproba": "^1.0.3 || ^2.0.0",
+ "color-support": "^1.1.2",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.1",
+ "object-assign": "^4.1.1",
+ "signal-exit": "^3.0.0",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1",
+ "wide-align": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/github-slugger": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz",
+ "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==",
+ "dev": true
+ },
+ "node_modules/glob": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "devOptional": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.9",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
+ "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
+ },
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
+ "optional": true
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-cache-semantics": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
+ "optional": true
+ },
+ "node_modules/http-errors": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
+ "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
+ "dependencies": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/http-proxy-agent": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+ "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+ "optional": true,
+ "dependencies": {
+ "@tootallnate/once": "1",
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "optional": true,
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/humanize-ms": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+ "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+ "optional": true,
+ "dependencies": {
+ "ms": "^2.0.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
+ "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/import-lazy": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
+ "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "devOptional": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/infer-owner": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
+ "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
+ "optional": true
+ },
+ "node_modules/inflection": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz",
+ "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==",
+ "engines": [
+ "node >= 0.4.0"
+ ]
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "devOptional": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/ip-address": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
+ "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
+ "optional": true,
+ "dependencies": {
+ "jsbn": "1.1.0",
+ "sprintf-js": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-buffer": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+ "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.15.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz",
+ "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "devOptional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-lambda": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
+ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
+ "optional": true
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.0.0.tgz",
+ "integrity": "sha512-NXRbBtUdBioI73y/HmOhogw/U5msYPC9DAtGkJXeFcFWSFZw0mCUsPxk/snTuJHzNKA8kLBK4rH97RMB1BfCXw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "devOptional": true
+ },
+ "node_modules/jake": {
+ "version": "10.8.5",
+ "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
+ "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==",
+ "dependencies": {
+ "async": "^3.2.3",
+ "chalk": "^4.0.2",
+ "filelist": "^1.0.1",
+ "minimatch": "^3.0.4"
+ },
+ "bin": {
+ "jake": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jju": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
+ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA=="
+ },
+ "node_modules/jose": {
+ "version": "4.15.5",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz",
+ "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsbn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
+ "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
+ "optional": true
+ },
+ "node_modules/json-schema": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+ "dev": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz",
+ "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
+ "dev": true
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/long": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
+ "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
+ },
+ "node_modules/longest-streak": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.0.1.tgz",
+ "integrity": "sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg==",
+ "dev": true,
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "optional": true,
+ "dependencies": {
+ "semver": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/make-dir/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "optional": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
+ },
+ "node_modules/make-fetch-happen": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz",
+ "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==",
+ "optional": true,
+ "dependencies": {
+ "agentkeepalive": "^4.1.3",
+ "cacache": "^15.2.0",
+ "http-cache-semantics": "^4.1.0",
+ "http-proxy-agent": "^4.0.1",
+ "https-proxy-agent": "^5.0.0",
+ "is-lambda": "^1.0.1",
+ "lru-cache": "^6.0.0",
+ "minipass": "^3.1.3",
+ "minipass-collect": "^1.0.2",
+ "minipass-fetch": "^1.3.2",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.4",
+ "negotiator": "^0.6.2",
+ "promise-retry": "^2.0.1",
+ "socks-proxy-agent": "^6.0.0",
+ "ssri": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/mariadb": {
+ "version": "2.5.5",
+ "resolved": "https://registry.npmjs.org/mariadb/-/mariadb-2.5.5.tgz",
+ "integrity": "sha512-6dklvcKWuuaV1JjAwnE2ezR+jTt7JrZHftgeHHBmjB0wgfaUpdxol1DPWclwMcCrsO9yoM0FuCOiCcCgXc//9Q==",
+ "dependencies": {
+ "@types/geojson": "^7946.0.7",
+ "@types/node": "^14.14.28",
+ "denque": "^1.5.0",
+ "iconv-lite": "^0.6.3",
+ "long": "^4.0.0",
+ "moment-timezone": "^0.5.33",
+ "please-upgrade-node": "^3.2.0"
+ },
+ "engines": {
+ "node": ">= 10.13"
+ }
+ },
+ "node_modules/mariadb/node_modules/@types/node": {
+ "version": "14.18.29",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.29.tgz",
+ "integrity": "sha512-LhF+9fbIX4iPzhsRLpK5H7iPdvW8L4IwGciXQIOEcuF62+9nw/VQVsOViAOOGxY3OlOKGLFv0sWwJXdwQeTn6A=="
+ },
+ "node_modules/mariadb/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/markdown-table": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.2.tgz",
+ "integrity": "sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==",
+ "dev": true,
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/matchit": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/matchit/-/matchit-1.1.0.tgz",
+ "integrity": "sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==",
+ "dev": true,
+ "dependencies": {
+ "@arr/every": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/mdast-builder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/mdast-builder/-/mdast-builder-1.1.1.tgz",
+ "integrity": "sha512-a3KBk/LmYD6wKsWi8WJrGU/rXR4yuF4Men0JO0z6dSZCm5FrXXWTRDjqK0vGSqa+1M6p9edeuypZAZAzSehTUw==",
+ "dev": true,
+ "dependencies": {
+ "@types/unist": "^2.0.3"
+ }
+ },
+ "node_modules/mdast-util-find-and-replace": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.1.0.tgz",
+ "integrity": "sha512-1w1jbqAd13oU78QPBf5223+xB+37ecNtQ1JElq2feWols5oEYAl+SgNDnOZipe7NfLemoEt362yUS15/wip4mw==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^5.0.0",
+ "unist-util-is": "^5.0.0",
+ "unist-util-visit-parents": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mdast-util-from-markdown": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz",
+ "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==",
+ "dev": true,
+ "dependencies": {
+ "@types/mdast": "^3.0.0",
+ "@types/unist": "^2.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "mdast-util-to-string": "^3.1.0",
+ "micromark": "^3.0.0",
+ "micromark-util-decode-numeric-character-reference": "^1.0.0",
+ "micromark-util-decode-string": "^1.0.0",
+ "micromark-util-normalize-identifier": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "unist-util-stringify-position": "^3.0.0",
+ "uvu": "^0.5.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.1.tgz",
+ "integrity": "sha512-42yHBbfWIFisaAfV1eixlabbsa6q7vHeSPY+cg+BBjX51M8xhgMacqH9g6TftB/9+YkcI0ooV4ncfrJslzm/RQ==",
+ "dev": true,
+ "dependencies": {
+ "mdast-util-from-markdown": "^1.0.0",
+ "mdast-util-gfm-autolink-literal": "^1.0.0",
+ "mdast-util-gfm-footnote": "^1.0.0",
+ "mdast-util-gfm-strikethrough": "^1.0.0",
+ "mdast-util-gfm-table": "^1.0.0",
+ "mdast-util-gfm-task-list-item": "^1.0.0",
+ "mdast-util-to-markdown": "^1.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-autolink-literal": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.2.tgz",
+ "integrity": "sha512-FzopkOd4xTTBeGXhXSBU0OCDDh5lUj2rd+HQqG92Ld+jL4lpUfgX2AT2OHAVP9aEeDKp7G92fuooSZcYJA3cRg==",
+ "dev": true,
+ "dependencies": {
+ "@types/mdast": "^3.0.0",
+ "ccount": "^2.0.0",
+ "mdast-util-find-and-replace": "^2.0.0",
+ "micromark-util-character": "^1.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-footnote": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.1.tgz",
+ "integrity": "sha512-p+PrYlkw9DeCRkTVw1duWqPRHX6Ywh2BNKJQcZbCwAuP/59B0Lk9kakuAd7KbQprVO4GzdW8eS5++A9PUSqIyw==",
+ "dev": true,
+ "dependencies": {
+ "@types/mdast": "^3.0.0",
+ "mdast-util-to-markdown": "^1.3.0",
+ "micromark-util-normalize-identifier": "^1.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-strikethrough": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.1.tgz",
+ "integrity": "sha512-zKJbEPe+JP6EUv0mZ0tQUyLQOC+FADt0bARldONot/nefuISkaZFlmVK4tU6JgfyZGrky02m/I6PmehgAgZgqg==",
+ "dev": true,
+ "dependencies": {
+ "@types/mdast": "^3.0.0",
+ "mdast-util-to-markdown": "^1.3.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-table": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.4.tgz",
+ "integrity": "sha512-aEuoPwZyP4iIMkf2cLWXxx3EQ6Bmh2yKy9MVCg4i6Sd3cX80dcLEfXO/V4ul3pGH9czBK4kp+FAl+ZHmSUt9/w==",
+ "dev": true,
+ "dependencies": {
+ "markdown-table": "^3.0.0",
+ "mdast-util-from-markdown": "^1.0.0",
+ "mdast-util-to-markdown": "^1.3.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-task-list-item": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.1.tgz",
+ "integrity": "sha512-KZ4KLmPdABXOsfnM6JHUIjxEvcx2ulk656Z/4Balw071/5qgnhz+H1uGtf2zIGnrnvDC8xR4Fj9uKbjAFGNIeA==",
+ "dev": true,
+ "dependencies": {
+ "@types/mdast": "^3.0.0",
+ "mdast-util-to-markdown": "^1.3.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-to-markdown": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.3.0.tgz",
+ "integrity": "sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA==",
+ "dev": true,
+ "dependencies": {
+ "@types/mdast": "^3.0.0",
+ "@types/unist": "^2.0.0",
+ "longest-streak": "^3.0.0",
+ "mdast-util-to-string": "^3.0.0",
+ "micromark-util-decode-string": "^1.0.0",
+ "unist-util-visit": "^4.0.0",
+ "zwitch": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-to-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz",
+ "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==",
+ "dev": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/micromark": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz",
+ "integrity": "sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "@types/debug": "^4.0.0",
+ "debug": "^4.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "micromark-core-commonmark": "^1.0.1",
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-combine-extensions": "^1.0.0",
+ "micromark-util-decode-numeric-character-reference": "^1.0.0",
+ "micromark-util-encode": "^1.0.0",
+ "micromark-util-normalize-identifier": "^1.0.0",
+ "micromark-util-resolve-all": "^1.0.0",
+ "micromark-util-sanitize-uri": "^1.0.0",
+ "micromark-util-subtokenize": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.1",
+ "uvu": "^0.5.0"
+ }
+ },
+ "node_modules/micromark-core-commonmark": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz",
+ "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "decode-named-character-reference": "^1.0.0",
+ "micromark-factory-destination": "^1.0.0",
+ "micromark-factory-label": "^1.0.0",
+ "micromark-factory-space": "^1.0.0",
+ "micromark-factory-title": "^1.0.0",
+ "micromark-factory-whitespace": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-classify-character": "^1.0.0",
+ "micromark-util-html-tag-name": "^1.0.0",
+ "micromark-util-normalize-identifier": "^1.0.0",
+ "micromark-util-resolve-all": "^1.0.0",
+ "micromark-util-subtokenize": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.1",
+ "uvu": "^0.5.0"
+ }
+ },
+ "node_modules/micromark-extension-gfm": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.1.tgz",
+ "integrity": "sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA==",
+ "dev": true,
+ "dependencies": {
+ "micromark-extension-gfm-autolink-literal": "^1.0.0",
+ "micromark-extension-gfm-footnote": "^1.0.0",
+ "micromark-extension-gfm-strikethrough": "^1.0.0",
+ "micromark-extension-gfm-table": "^1.0.0",
+ "micromark-extension-gfm-tagfilter": "^1.0.0",
+ "micromark-extension-gfm-task-list-item": "^1.0.0",
+ "micromark-util-combine-extensions": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-autolink-literal": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.3.tgz",
+ "integrity": "sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg==",
+ "dev": true,
+ "dependencies": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-sanitize-uri": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-footnote": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.4.tgz",
+ "integrity": "sha512-E/fmPmDqLiMUP8mLJ8NbJWJ4bTw6tS+FEQS8CcuDtZpILuOb2kjLqPEeAePF1djXROHXChM/wPJw0iS4kHCcIg==",
+ "dev": true,
+ "dependencies": {
+ "micromark-core-commonmark": "^1.0.0",
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-normalize-identifier": "^1.0.0",
+ "micromark-util-sanitize-uri": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-strikethrough": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.4.tgz",
+ "integrity": "sha512-/vjHU/lalmjZCT5xt7CcHVJGq8sYRm80z24qAKXzaHzem/xsDYb2yLL+NNVbYvmpLx3O7SYPuGL5pzusL9CLIQ==",
+ "dev": true,
+ "dependencies": {
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-classify-character": "^1.0.0",
+ "micromark-util-resolve-all": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-table": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz",
+ "integrity": "sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg==",
+ "dev": true,
+ "dependencies": {
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-tagfilter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.1.tgz",
+ "integrity": "sha512-Ty6psLAcAjboRa/UKUbbUcwjVAv5plxmpUTy2XC/3nJFL37eHej8jrHrRzkqcpipJliuBH30DTs7+3wqNcQUVA==",
+ "dev": true,
+ "dependencies": {
+ "micromark-util-types": "^1.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-task-list-item": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.3.tgz",
+ "integrity": "sha512-PpysK2S1Q/5VXi72IIapbi/jliaiOFzv7THH4amwXeYXLq3l1uo8/2Be0Ac1rEwK20MQEsGH2ltAZLNY2KI/0Q==",
+ "dev": true,
+ "dependencies": {
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-factory-destination": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz",
+ "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-factory-label": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz",
+ "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "node_modules/micromark-factory-space": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz",
+ "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-factory-title": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz",
+ "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "node_modules/micromark-factory-whitespace": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz",
+ "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-character": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz",
+ "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-chunked": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz",
+ "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-classify-character": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz",
+ "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-combine-extensions": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz",
+ "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-decode-numeric-character-reference": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz",
+ "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-decode-string": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz",
+ "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "decode-named-character-reference": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-decode-numeric-character-reference": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-encode": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz",
+ "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ]
+ },
+ "node_modules/micromark-util-html-tag-name": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.0.0.tgz",
+ "integrity": "sha512-NenEKIshW2ZI/ERv9HtFNsrn3llSPZtY337LID/24WeLqMzeZhBEE6BQ0vS2ZBjshm5n40chKtJ3qjAbVV8S0g==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ]
+ },
+ "node_modules/micromark-util-normalize-identifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz",
+ "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-resolve-all": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz",
+ "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-sanitize-uri": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz",
+ "integrity": "sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-encode": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-subtokenize": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz",
+ "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "node_modules/micromark-util-symbol": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz",
+ "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ]
+ },
+ "node_modules/micromark-util-types": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz",
+ "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ]
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.51.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
+ "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.34",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
+ "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
+ "dependencies": {
+ "mime-db": "1.51.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "optional": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minipass-collect": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz",
+ "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/minipass-fetch": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz",
+ "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.1.0",
+ "minipass-sized": "^1.0.3",
+ "minizlib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "optionalDependencies": {
+ "encoding": "^0.1.12"
+ }
+ },
+ "node_modules/minipass-flush": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
+ "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/minipass-pipeline": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
+ "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minipass-sized": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz",
+ "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "optional": true,
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/moment": {
+ "version": "2.29.4",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/moment-timezone": {
+ "version": "0.5.37",
+ "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.37.tgz",
+ "integrity": "sha512-uEDzDNFhfaywRl+vwXxffjjq1q0Vzr+fcQpQ1bU0kbzorfS7zVtZnCnGc8mhWmF39d4g4YriF6kwA75mJKE/Zg==",
+ "dependencies": {
+ "moment": ">= 2.9.0"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/mri": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/node-addon-api": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+ "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
+ "optional": true
+ },
+ "node_modules/node-fetch": {
+ "version": "2.6.11",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
+ "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
+ "optional": true,
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-fetch/node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "optional": true
+ },
+ "node_modules/node-fetch/node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "optional": true
+ },
+ "node_modules/node-fetch/node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "optional": true,
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/node-gyp": {
+ "version": "8.4.1",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz",
+ "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==",
+ "optional": true,
+ "dependencies": {
+ "env-paths": "^2.2.0",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.6",
+ "make-fetch-happen": "^9.1.0",
+ "nopt": "^5.0.0",
+ "npmlog": "^6.0.0",
+ "rimraf": "^3.0.2",
+ "semver": "^7.3.5",
+ "tar": "^6.1.2",
+ "which": "^2.0.2"
+ },
+ "bin": {
+ "node-gyp": "bin/node-gyp.js"
+ },
+ "engines": {
+ "node": ">= 10.12.0"
+ }
+ },
+ "node_modules/node-gyp/node_modules/are-we-there-yet": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz",
+ "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==",
+ "optional": true,
+ "dependencies": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/node-gyp/node_modules/gauge": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz",
+ "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==",
+ "optional": true,
+ "dependencies": {
+ "aproba": "^1.0.3 || ^2.0.0",
+ "color-support": "^1.1.3",
+ "console-control-strings": "^1.1.0",
+ "has-unicode": "^2.0.1",
+ "signal-exit": "^3.0.7",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1",
+ "wide-align": "^1.1.5"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/node-gyp/node_modules/npmlog": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz",
+ "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==",
+ "optional": true,
+ "dependencies": {
+ "are-we-there-yet": "^3.0.0",
+ "console-control-strings": "^1.1.0",
+ "gauge": "^4.0.3",
+ "set-blocking": "^2.0.0"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/nodemailer": {
+ "version": "6.9.9",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.9.tgz",
+ "integrity": "sha512-dexTll8zqQoVJEZPwQAKzxxtFn0qTnjdQTchoU6Re9BUUGBJiOy3YMn/0ShTW6J5M0dfQ1NeDeRTTl4oIWgQMA==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/nopt": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+ "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+ "optional": true,
+ "dependencies": {
+ "abbrev": "1"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/npmlog": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
+ "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
+ "optional": true,
+ "dependencies": {
+ "are-we-there-yet": "^2.0.0",
+ "console-control-strings": "^1.1.0",
+ "gauge": "^3.0.0",
+ "set-blocking": "^2.0.0"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
+ "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "devOptional": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
+ "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
+ "dev": true,
+ "dependencies": {
+ "@aashutoshrathi/word-wrap": "^1.2.3",
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "optional": true,
+ "dependencies": {
+ "aggregate-error": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/packet-reader": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
+ "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ=="
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "devOptional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pg": {
+ "version": "8.7.1",
+ "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz",
+ "integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==",
+ "dependencies": {
+ "buffer-writer": "2.0.0",
+ "packet-reader": "1.0.0",
+ "pg-connection-string": "^2.5.0",
+ "pg-pool": "^3.4.1",
+ "pg-protocol": "^1.5.0",
+ "pg-types": "^2.1.0",
+ "pgpass": "1.x"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ },
+ "peerDependencies": {
+ "pg-native": ">=2.0.0"
+ },
+ "peerDependenciesMeta": {
+ "pg-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/pg-connection-string": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
+ "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
+ },
+ "node_modules/pg-hstore": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.4.tgz",
+ "integrity": "sha512-N3SGs/Rf+xA1M2/n0JBiXFDVMzdekwLZLAO0g7mpDY9ouX+fDI7jS6kTq3JujmYbtNSJ53TJ0q4G98KVZSM4EA==",
+ "dependencies": {
+ "underscore": "^1.13.1"
+ },
+ "engines": {
+ "node": ">= 0.8.x"
+ }
+ },
+ "node_modules/pg-int8": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
+ "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/pg-pool": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz",
+ "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==",
+ "peerDependencies": {
+ "pg": ">=8.0"
+ }
+ },
+ "node_modules/pg-protocol": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
+ "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ=="
+ },
+ "node_modules/pg-types": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
+ "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
+ "dependencies": {
+ "pg-int8": "1.0.1",
+ "postgres-array": "~2.0.0",
+ "postgres-bytea": "~1.0.0",
+ "postgres-date": "~1.0.4",
+ "postgres-interval": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/pgpass": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
+ "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
+ "dependencies": {
+ "split2": "^4.1.0"
+ }
+ },
+ "node_modules/phin": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz",
+ "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==",
+ "dev": true,
+ "dependencies": {
+ "centra": "^2.7.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/please-upgrade-node": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+ "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+ "dependencies": {
+ "semver-compare": "^1.0.0"
+ }
+ },
+ "node_modules/polka": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/polka/-/polka-0.5.2.tgz",
+ "integrity": "sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==",
+ "dev": true,
+ "dependencies": {
+ "@polka/url": "^0.5.0",
+ "trouter": "^2.0.1"
+ }
+ },
+ "node_modules/pony-cause": {
+ "version": "2.1.11",
+ "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz",
+ "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/postgres-array": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
+ "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postgres-bytea": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
+ "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postgres-date": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
+ "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postgres-interval": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
+ "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
+ "dependencies": {
+ "xtend": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/promise-inflight": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+ "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==",
+ "optional": true
+ },
+ "node_modules/promise-retry": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
+ "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+ "optional": true,
+ "dependencies": {
+ "err-code": "^2.0.2",
+ "retry": "^0.12.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
+ "dependencies": {
+ "side-channel": "^1.0.6"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/rate-limiter-flexible": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.3.6.tgz",
+ "integrity": "sha512-8DVFOe89rreyut/vzwBI7vgXJynyYoYnH5XogtAKs0F/neAbCTTglXxSJ7fZeZamcFXZDvMidCBvps4KM+1srw=="
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/raw-body/node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/raw-body/node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/raw-body/node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "optional": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/remark-gfm": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz",
+ "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==",
+ "dev": true,
+ "dependencies": {
+ "@types/mdast": "^3.0.0",
+ "mdast-util-gfm": "^2.0.0",
+ "micromark-extension-gfm": "^2.0.0",
+ "unified": "^10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-parse": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz",
+ "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==",
+ "dev": true,
+ "dependencies": {
+ "@types/mdast": "^3.0.0",
+ "mdast-util-from-markdown": "^1.0.0",
+ "unified": "^10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-stringify": {
+ "version": "10.0.2",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-10.0.2.tgz",
+ "integrity": "sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw==",
+ "dev": true,
+ "dependencies": {
+ "@types/mdast": "^3.0.0",
+ "mdast-util-to-markdown": "^1.0.0",
+ "unified": "^10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+ "optional": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/retry-as-promised": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.0.4.tgz",
+ "integrity": "sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA=="
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "devOptional": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/sade": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
+ "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
+ "dev": true,
+ "dependencies": {
+ "mri": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/safe-stable-stringify": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz",
+ "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/semver-compare": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+ "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w="
+ },
+ "node_modules/send": {
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+ "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/send/node_modules/debug/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/send/node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/send/node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/send/node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/sequelize": {
+ "version": "6.29.0",
+ "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.29.0.tgz",
+ "integrity": "sha512-m8Wi90rs3NZP9coXE52c7PL4Q078nwYZXqt1IxPvgki7nOFn0p/F0eKsYDBXCPw9G8/BCEa6zZNk0DQUAT4ypA==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/sequelize"
+ }
+ ],
+ "dependencies": {
+ "@types/debug": "^4.1.7",
+ "@types/validator": "^13.7.1",
+ "debug": "^4.3.3",
+ "dottie": "^2.0.2",
+ "inflection": "^1.13.2",
+ "lodash": "^4.17.21",
+ "moment": "^2.29.1",
+ "moment-timezone": "^0.5.35",
+ "pg-connection-string": "^2.5.0",
+ "retry-as-promised": "^7.0.3",
+ "semver": "^7.3.5",
+ "sequelize-pool": "^7.1.0",
+ "toposort-class": "^1.0.1",
+ "uuid": "^8.3.2",
+ "validator": "^13.7.0",
+ "wkx": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ibm_db": {
+ "optional": true
+ },
+ "mariadb": {
+ "optional": true
+ },
+ "mysql2": {
+ "optional": true
+ },
+ "oracledb": {
+ "optional": true
+ },
+ "pg": {
+ "optional": true
+ },
+ "pg-hstore": {
+ "optional": true
+ },
+ "snowflake-sdk": {
+ "optional": true
+ },
+ "sqlite3": {
+ "optional": true
+ },
+ "tedious": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/sequelize-pool": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-7.1.0.tgz",
+ "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+ "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
+ "dependencies": {
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.19.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/serve-static/node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+ "optional": true
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "optional": true
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+ "optional": true,
+ "engines": {
+ "node": ">= 6.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socket.io": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz",
+ "integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==",
+ "dependencies": {
+ "accepts": "~1.3.4",
+ "base64id": "~2.0.0",
+ "cors": "~2.8.5",
+ "debug": "~4.3.2",
+ "engine.io": "~6.6.0",
+ "socket.io-adapter": "~2.5.2",
+ "socket.io-parser": "~4.2.4"
+ },
+ "engines": {
+ "node": ">=10.2.0"
+ }
+ },
+ "node_modules/socket.io-adapter": {
+ "version": "2.5.5",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
+ "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
+ "dependencies": {
+ "debug": "~4.3.4",
+ "ws": "~8.17.1"
+ }
+ },
+ "node_modules/socket.io-parser": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
+ "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
+ "dependencies": {
+ "@socket.io/component-emitter": "~3.1.0",
+ "debug": "~4.3.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/socks": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
+ "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
+ "optional": true,
+ "dependencies": {
+ "ip-address": "^9.0.5",
+ "smart-buffer": "^4.2.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks-proxy-agent": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz",
+ "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==",
+ "optional": true,
+ "dependencies": {
+ "agent-base": "^6.0.2",
+ "debug": "^4.3.3",
+ "socks": "^2.6.2"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/split2": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz",
+ "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==",
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
+ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
+ "optional": true
+ },
+ "node_modules/sqlite3": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.6.tgz",
+ "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==",
+ "hasInstallScript": true,
+ "optional": true,
+ "dependencies": {
+ "@mapbox/node-pre-gyp": "^1.0.0",
+ "node-addon-api": "^4.2.0",
+ "tar": "^6.1.11"
+ },
+ "optionalDependencies": {
+ "node-gyp": "8.x"
+ },
+ "peerDependencies": {
+ "node-gyp": "8.x"
+ },
+ "peerDependenciesMeta": {
+ "node-gyp": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ssri": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
+ "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.1.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "optional": true,
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string_decoder/node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "optional": true
+ },
+ "node_modules/string-argv": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
+ "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
+ "engines": {
+ "node": ">=0.6.19"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "devOptional": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "devOptional": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/tar": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+ "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
+ "optional": true,
+ "dependencies": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^5.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/tar/node_modules/minipass": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
+ "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/toposort-class": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz",
+ "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg="
+ },
+ "node_modules/trough": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz",
+ "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==",
+ "dev": true,
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/trouter": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/trouter/-/trouter-2.0.1.tgz",
+ "integrity": "sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==",
+ "dev": true,
+ "dependencies": {
+ "matchit": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ts-api-utils": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
+ "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=16"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.2.0"
+ }
+ },
+ "node_modules/ts-node": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz",
+ "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==",
+ "dev": true,
+ "dependencies": {
+ "@cspotcode/source-map-support": "0.7.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ts-node/node_modules/acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
+ "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/typescript-json-schema": {
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.52.0.tgz",
+ "integrity": "sha512-3ZdHzx116gZ+D9LmMl5/+d1G3Rpt8baWngKzepYWHnXbAa8Winv64CmFRqLlMKneE1c40yugYDFcWdyX1FjGzQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "@types/node": "^16.9.2",
+ "glob": "^7.1.7",
+ "safe-stable-stringify": "^2.2.0",
+ "ts-node": "^10.2.1",
+ "typescript": "~4.4.4",
+ "yargs": "^17.1.1"
+ },
+ "bin": {
+ "typescript-json-schema": "bin/typescript-json-schema"
+ }
+ },
+ "node_modules/typescript-json-schema/node_modules/typescript": {
+ "version": "4.4.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
+ "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/umzug": {
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/umzug/-/umzug-3.8.1.tgz",
+ "integrity": "sha512-k0HjOc3b/s8vH24BUTvnaFiKhfWI9UQAGpqHDG+3866CGlBTB83Xs5wZ1io1mwYLj/GHvQ34AxKhbpYnWtkRJg==",
+ "dependencies": {
+ "@rushstack/ts-command-line": "^4.12.2",
+ "emittery": "^0.13.0",
+ "fast-glob": "^3.3.2",
+ "pony-cause": "^2.1.4",
+ "type-fest": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/umzug/node_modules/type-fest": {
+ "version": "4.23.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.23.0.tgz",
+ "integrity": "sha512-ZiBujro2ohr5+Z/hZWHESLz3g08BBdrdLMieYFULJO+tWc437sn8kQsWLJoZErY8alNhxre9K4p3GURAG11n+w==",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/underscore": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.2.tgz",
+ "integrity": "sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g=="
+ },
+ "node_modules/unified": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.1.tgz",
+ "integrity": "sha512-v4ky1+6BN9X3pQrOdkFIPWAaeDsHPE1svRDxq7YpTc2plkIqFMwukfqM+l0ewpP9EfwARlt9pPFAeWYhHm8X9w==",
+ "dev": true,
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "bail": "^2.0.0",
+ "extend": "^3.0.0",
+ "is-buffer": "^2.0.0",
+ "is-plain-obj": "^4.0.0",
+ "trough": "^2.0.0",
+ "vfile": "^5.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unique-filename": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
+ "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
+ "optional": true,
+ "dependencies": {
+ "unique-slug": "^2.0.0"
+ }
+ },
+ "node_modules/unique-slug": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz",
+ "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==",
+ "optional": true,
+ "dependencies": {
+ "imurmurhash": "^0.1.4"
+ }
+ },
+ "node_modules/unist-util-inspect": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-inspect/-/unist-util-inspect-7.0.0.tgz",
+ "integrity": "sha512-2Utgv78I7PUu461Y9cdo+IUiiKSKpDV5CE/XD6vTj849a3xlpDAScvSJ6cQmtFBGgAmCn2wR7jLuXhpg1XLlJw==",
+ "dev": true,
+ "dependencies": {
+ "@types/unist": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-is": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz",
+ "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==",
+ "dev": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-stringify-position": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz",
+ "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==",
+ "dev": true,
+ "dependencies": {
+ "@types/unist": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-visit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.0.tgz",
+ "integrity": "sha512-n7lyhFKJfVZ9MnKtqbsqkQEk5P1KShj0+//V7mAcoI6bpbUjh3C/OG8HVD+pBihfh6Ovl01m8dkcv9HNqYajmQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^5.0.0",
+ "unist-util-visit-parents": "^5.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-visit-parents": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz",
+ "integrity": "sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw==",
+ "dev": true,
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^5.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-visit/node_modules/unist-util-visit-parents": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.0.tgz",
+ "integrity": "sha512-y+QVLcY5eR/YVpqDsLf/xh9R3Q2Y4HxkZTp7ViLDU6WtJCEcPmRzW1gpdWDCDIqIlhuPDXOgttqPlykrHYDekg==",
+ "dev": true,
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^5.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "optional": true
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/uvu": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.3.tgz",
+ "integrity": "sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw==",
+ "dev": true,
+ "dependencies": {
+ "dequal": "^2.0.0",
+ "diff": "^5.0.0",
+ "kleur": "^4.0.3",
+ "sade": "^1.7.3"
+ },
+ "bin": {
+ "uvu": "bin.js"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/uvu/node_modules/diff": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/validator": {
+ "version": "13.7.0",
+ "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz",
+ "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/vfile": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.2.tgz",
+ "integrity": "sha512-w0PLIugRY3Crkgw89TeMvHCzqCs/zpreR31hl4D92y6SOE07+bfJe+dK5Q2akwS+i/c801kzjoOr9gMcTe6IAA==",
+ "dev": true,
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "is-buffer": "^2.0.0",
+ "unist-util-stringify-position": "^3.0.0",
+ "vfile-message": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/vfile-message": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz",
+ "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==",
+ "dev": true,
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "unist-util-stringify-position": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "devOptional": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/wide-align": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
+ "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
+ "optional": true,
+ "dependencies": {
+ "string-width": "^1.0.2 || 2 || 3 || 4"
+ }
+ },
+ "node_modules/wkx": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz",
+ "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "devOptional": true
+ },
+ "node_modules/ws": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+ "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
+ "node_modules/xxhashjs": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz",
+ "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==",
+ "dev": true,
+ "dependencies": {
+ "cuint": "^0.2.2"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ },
+ "node_modules/yargs": {
+ "version": "17.3.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz",
+ "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.0.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz",
+ "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zwitch": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.2.tgz",
+ "integrity": "sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA==",
+ "dev": true,
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ }
+ },
+ "dependencies": {
+ "@aashutoshrathi/word-wrap": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
+ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
+ "dev": true
+ },
+ "@adobe/helix-log": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@adobe/helix-log/-/helix-log-6.0.0.tgz",
+ "integrity": "sha512-+9gpf49sFDmZLV3gtjY+RmEUistqYJdVWpiqlRYpxE59x5bHFzYf93dZ7fljSTBtZdVq8lm97HxrTUloh5HvRg==",
"dev": true,
"requires": {
- "@adobe/helix-log": "4.5.1",
+ "big.js": "^6.1.1",
+ "colorette": "^2.0.2",
+ "ferrum": "^1.9.3",
+ "phin": "^3.6.0",
+ "polka": "^0.5.2"
+ }
+ },
+ "@adobe/jsonschema2md": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@adobe/jsonschema2md/-/jsonschema2md-7.0.0.tgz",
+ "integrity": "sha512-kmAtrV8ljQcmPiPadMG6a/8XorXsZKP8LQKdkKSeaGb91E+hXO1/lfxa8+s1gAtnwJi2MwzmFl4/TjcCkkxesw==",
+ "dev": true,
+ "requires": {
+ "@adobe/helix-log": "6.0.0",
+ "@types/json-schema": "^7.0.8",
+ "@types/mdast": "^3.0.4",
"es2015-i18n-tag": "1.6.1",
- "ferrum": "1.7.0",
- "fs-extra": "8.1.0",
- "github-slugger": "1.3.0",
- "js-yaml": "3.13.1",
+ "ferrum": "1.9.4",
+ "fs-extra": "10.0.0",
+ "github-slugger": "1.4.0",
+ "js-yaml": "4.1.0",
+ "json-schema": "^0.4.0",
"mdast-builder": "1.1.1",
- "mdast-util-to-string": "1.1.0",
- "readdirp": "3.3.0",
- "remark-parse": "7.0.2",
- "remark-stringify": "7.0.4",
- "unified": "8.4.2",
- "unist-util-inspect": "5.0.1",
- "yargs": "15.3.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
- "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
- "dev": true
- },
- "ansi-styles": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
- "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
- "dev": true,
- "requires": {
- "@types/color-name": "1.1.1",
- "color-convert": "2.0.1"
- }
- },
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true
- },
- "cliui": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
- "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
- "dev": true,
- "requires": {
- "string-width": "4.2.0",
- "strip-ansi": "6.0.0",
- "wrap-ansi": "6.2.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "requires": {
- "locate-path": "5.0.0",
- "path-exists": "4.0.0"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "requires": {
- "p-locate": "4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "requires": {
- "p-limit": "2.2.2"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true
- },
- "string-width": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
- "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
- "dev": true,
- "requires": {
- "emoji-regex": "8.0.0",
- "is-fullwidth-code-point": "3.0.0",
- "strip-ansi": "6.0.0"
- }
- },
- "strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "dev": true,
- "requires": {
- "ansi-regex": "5.0.0"
- }
- },
- "wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "dev": true,
- "requires": {
- "ansi-styles": "4.2.1",
- "string-width": "4.2.0",
- "strip-ansi": "6.0.0"
- }
- },
- "yargs": {
- "version": "15.3.1",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
- "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==",
- "dev": true,
- "requires": {
- "cliui": "6.0.0",
- "decamelize": "1.2.0",
- "find-up": "4.1.0",
- "get-caller-file": "2.0.5",
- "require-directory": "2.1.1",
- "require-main-filename": "2.0.0",
- "set-blocking": "2.0.0",
- "string-width": "4.2.0",
- "which-module": "2.0.0",
- "y18n": "4.0.0",
- "yargs-parser": "18.1.3"
- }
- },
- "yargs-parser": {
- "version": "18.1.3",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
- "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
- "dev": true,
- "requires": {
- "camelcase": "5.3.1",
- "decamelize": "1.2.0"
- }
- }
+ "mdast-util-to-string": "3.1.0",
+ "readdirp": "3.6.0",
+ "remark-gfm": "^3.0.0",
+ "remark-parse": "10.0.1",
+ "remark-stringify": "10.0.2",
+ "unified": "10.1.1",
+ "unist-util-inspect": "7.0.0",
+ "yargs": "17.3.1"
}
},
"@arr/every": {
@@ -212,331 +6150,610 @@
"integrity": "sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==",
"dev": true
},
- "@babel/code-frame": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
- "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
- "dev": true,
- "requires": {
- "@babel/highlight": "7.10.4"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
- "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
+ "@cspotcode/source-map-consumer": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
+ "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
"dev": true
},
- "@babel/highlight": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
- "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
+ "@cspotcode/source-map-support": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
+ "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "7.10.4",
- "chalk": "2.4.2",
- "js-tokens": "4.0.0"
+ "@cspotcode/source-map-consumer": "0.8.0"
}
},
- "@babel/runtime": {
- "version": "7.9.2",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz",
- "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==",
+ "@eslint-community/eslint-utils": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+ "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "dev": true,
"requires": {
- "regenerator-runtime": "0.13.5"
+ "eslint-visitor-keys": "^3.3.0"
}
},
- "@hapi/boom": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.0.tgz",
- "integrity": "sha512-4nZmpp4tXbm162LaZT45P7F7sgiem8dwAh2vHWT6XX24dozNjGMg6BvKCRvtCUcmcXqeMIUqWN8Rc5X8yKuROQ==",
- "requires": {
- "@hapi/hoek": "9.0.4"
- }
+ "@eslint-community/regexpp": {
+ "version": "4.11.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz",
+ "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==",
+ "dev": true
},
- "@hapi/hoek": {
- "version": "9.0.4",
- "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.0.4.tgz",
- "integrity": "sha512-EwaJS7RjoXUZ2cXXKZZxZqieGtc7RbvQhUy8FwDoMQtxWVi14tFjeFCYPZAM1mBCpOpiBpyaZbb9NeHc7eGKgw=="
- },
- "@ladjs/i18n": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/@ladjs/i18n/-/i18n-3.0.4.tgz",
- "integrity": "sha512-b6aL/9T16ynvFUZFlsJ4VmKyjqb3jbCv+SOS5pkaAnfXiID/HWtPUlLHKK47SEjLmRJLiIyblVccjNyE/brRaw==",
+ "@eslint/eslintrc": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "dev": true,
"requires": {
- "@hapi/boom": "9.1.0",
- "boolean": "3.0.0",
- "country-language": "0.1.7",
- "debug": "4.1.1",
- "i18n": "0.8.6",
- "i18n-locales": "0.0.4",
- "lodash": "4.17.19",
- "moment": "2.24.0",
- "multimatch": "4.0.0",
- "qs": "6.9.3",
- "titleize": "2.1.0"
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.6.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
},
"dependencies": {
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
"requires": {
- "ms": "2.1.2"
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
}
},
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "qs": {
- "version": "6.9.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz",
- "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw=="
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
}
}
},
+ "@eslint/js": {
+ "version": "8.57.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
+ "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+ "dev": true
+ },
+ "@gar/promisify": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
+ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==",
+ "optional": true
+ },
+ "@humanwhocodes/config-array": {
+ "version": "0.11.14",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
+ "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
+ "dev": true,
+ "requires": {
+ "@humanwhocodes/object-schema": "^2.0.2",
+ "debug": "^4.3.1",
+ "minimatch": "^3.0.5"
+ }
+ },
+ "@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true
+ },
+ "@humanwhocodes/object-schema": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+ "dev": true
+ },
+ "@mapbox/node-pre-gyp": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz",
+ "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==",
+ "optional": true,
+ "requires": {
+ "detect-libc": "^2.0.0",
+ "https-proxy-agent": "^5.0.0",
+ "make-dir": "^3.1.0",
+ "node-fetch": "^2.6.7",
+ "nopt": "^5.0.0",
+ "npmlog": "^5.0.1",
+ "rimraf": "^3.0.2",
+ "semver": "^7.3.5",
+ "tar": "^6.1.11"
+ }
+ },
+ "@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "requires": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ }
+ },
+ "@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="
+ },
+ "@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "requires": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ }
+ },
+ "@npmcli/fs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz",
+ "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==",
+ "optional": true,
+ "requires": {
+ "@gar/promisify": "^1.0.1",
+ "semver": "^7.3.5"
+ }
+ },
+ "@npmcli/move-file": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
+ "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==",
+ "optional": true,
+ "requires": {
+ "mkdirp": "^1.0.4",
+ "rimraf": "^3.0.2"
+ }
+ },
"@polka/url": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz",
"integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==",
"dev": true
},
- "@sindresorhus/is": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.0.tgz",
- "integrity": "sha512-lXKXfypKo644k4Da4yXkPCrwcvn6SlUW2X2zFbuflKHNjf0w9htru01bo26uMhleMXsDmnZ12eJLdrAZa9MANg=="
- },
- "@types/babel-types": {
- "version": "7.0.7",
- "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.7.tgz",
- "integrity": "sha512-dBtBbrc+qTHy1WdfHYjBwRln4+LWqASWakLHsWHR2NWHIFkv4W3O070IGoGLEBrJBvct3r0L1BUPuvURi7kYUQ=="
- },
- "@types/babylon": {
- "version": "6.16.5",
- "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.5.tgz",
- "integrity": "sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==",
+ "@rushstack/node-core-library": {
+ "version": "5.5.1",
+ "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.5.1.tgz",
+ "integrity": "sha512-ZutW56qIzH8xIOlfyaLQJFx+8IBqdbVCZdnj+XT1MorQ1JqqxHse8vbCpEM+2MjsrqcbxcgDIbfggB1ZSQ2A3g==",
"requires": {
- "@types/babel-types": "7.0.7"
+ "ajv": "~8.13.0",
+ "ajv-draft-04": "~1.0.0",
+ "ajv-formats": "~3.0.1",
+ "fs-extra": "~7.0.1",
+ "import-lazy": "~4.0.0",
+ "jju": "~1.4.0",
+ "resolve": "~1.22.1",
+ "semver": "~7.5.4"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "8.13.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz",
+ "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==",
+ "requires": {
+ "fast-deep-equal": "^3.1.3",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.4.1"
+ }
+ },
+ "ajv-draft-04": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz",
+ "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==",
+ "requires": {}
+ },
+ "fs-extra": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
+ }
}
},
+ "@rushstack/terminal": {
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.13.3.tgz",
+ "integrity": "sha512-fc3zjXOw8E0pXS5t9vTiIPx9gHA0fIdTXsu9mT4WbH+P3mYvnrX0iAQ5a6NvyK1+CqYWBTw/wVNx7SDJkI+WYQ==",
+ "requires": {
+ "@rushstack/node-core-library": "5.5.1",
+ "supports-color": "~8.1.1"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "@rushstack/ts-command-line": {
+ "version": "4.22.3",
+ "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.22.3.tgz",
+ "integrity": "sha512-edMpWB3QhFFZ4KtSzS8WNjBgR4PXPPOVrOHMbb7kNpmQ1UFS9HdVtjCXg1H5fG+xYAbeE+TMPcVPUyX2p84STA==",
+ "requires": {
+ "@rushstack/terminal": "0.13.3",
+ "@types/argparse": "1.0.38",
+ "argparse": "~1.0.9",
+ "string-argv": "~0.3.1"
+ },
+ "dependencies": {
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
+ }
+ }
+ },
+ "@socket.io/component-emitter": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
+ "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
+ },
+ "@tootallnate/once": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+ "optional": true
+ },
+ "@tsconfig/node10": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
+ "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
+ "dev": true
+ },
+ "@tsconfig/node12": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
+ "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
+ "dev": true
+ },
+ "@tsconfig/node14": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
+ "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
+ "dev": true
+ },
+ "@tsconfig/node16": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
+ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
+ "dev": true
+ },
+ "@types/argparse": {
+ "version": "1.0.38",
+ "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz",
+ "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA=="
+ },
"@types/basic-auth": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@types/basic-auth/-/basic-auth-1.1.3.tgz",
"integrity": "sha512-W3rv6J0IGlxqgE2eQ2pTb0gBjaGtejQpJ6uaCjz3UQ65+TFTPC5/lAE+POfx1YLdjtxvejJzsIAfd3MxWiVmfg==",
"dev": true,
"requires": {
- "@types/node": "12.12.32"
+ "@types/node": "*"
}
},
- "@types/bluebird": {
- "version": "3.5.30",
- "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.30.tgz",
- "integrity": "sha512-8LhzvcjIoqoi1TghEkRMkbbmM+jhHnBokPGkJWjclMK+Ks0MxEBow3/p2/iFTZ+OIbJHQDSfpgdZEb+af3gfVw==",
- "dev": true
- },
"@types/body-parser": {
- "version": "1.19.0",
- "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
- "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
+ "version": "1.19.2",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
+ "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
"dev": true,
"requires": {
- "@types/connect": "3.4.33",
- "@types/node": "12.12.32"
+ "@types/connect": "*",
+ "@types/node": "*"
}
},
- "@types/bson": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.2.tgz",
- "integrity": "sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q==",
- "dev": true,
- "requires": {
- "@types/node": "12.12.32"
- }
- },
- "@types/color-name": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
- "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
- "dev": true
- },
"@types/connect": {
- "version": "3.4.33",
- "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
- "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
+ "version": "3.4.35",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
+ "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
"dev": true,
"requires": {
- "@types/node": "12.12.32"
+ "@types/node": "*"
}
},
- "@types/continuation-local-storage": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/@types/continuation-local-storage/-/continuation-local-storage-3.2.2.tgz",
- "integrity": "sha512-aItm+aYPJ4rT1cHmAxO+OdWjSviQ9iB5UKb5f0Uvgln0N4hS2mcDodHtPiqicYBXViUYhqyBjhA5uyOcT+S34Q==",
- "dev": true,
+ "@types/cookie": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
+ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
+ },
+ "@types/cors": {
+ "version": "2.8.17",
+ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
+ "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
"requires": {
- "@types/node": "12.12.32"
+ "@types/node": "*"
}
},
- "@types/email-templates": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/@types/email-templates/-/email-templates-6.0.2.tgz",
- "integrity": "sha512-9pzmolar0fCWBm1xtp1CB3GI/9PRhxOGzQZG7cSx48vnesxF+F+JSzCtnfunYwCvx4TWKvb3QqbfTRps2g+KlA==",
- "dev": true,
+ "@types/debug": {
+ "version": "4.1.7",
+ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz",
+ "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==",
"requires": {
- "@types/html-to-text": "1.4.31",
- "@types/nodemailer": "6.4.0"
+ "@types/ms": "*"
}
},
+ "@types/ejs": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.0.tgz",
+ "integrity": "sha512-DCg+Ka+uDQ31lJ/UtEXVlaeV3d6t81gifaVWKJy4MYVVgvJttyX/viREy+If7fz+tK/gVxTGMtyrFPnm4gjrVA==",
+ "dev": true
+ },
"@types/express": {
- "version": "4.17.3",
- "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.3.tgz",
- "integrity": "sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg==",
+ "version": "4.17.13",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
+ "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
"dev": true,
"requires": {
- "@types/body-parser": "1.19.0",
- "@types/express-serve-static-core": "4.17.3",
- "@types/serve-static": "1.13.3"
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^4.17.18",
+ "@types/qs": "*",
+ "@types/serve-static": "*"
}
},
"@types/express-serve-static-core": {
- "version": "4.17.3",
- "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.3.tgz",
- "integrity": "sha512-sHEsvEzjqN+zLbqP+8OXTipc10yH1QLR+hnr5uw29gi9AhCAAAdri8ClNV7iMdrJrIzXIQtlkPvq8tJGhj3QJQ==",
+ "version": "4.17.28",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
+ "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
"dev": true,
"requires": {
- "@types/node": "12.12.32",
- "@types/range-parser": "1.2.3"
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*"
}
},
"@types/geojson": {
- "version": "7946.0.7",
- "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
- "integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ=="
- },
- "@types/html-to-text": {
- "version": "1.4.31",
- "resolved": "https://registry.npmjs.org/@types/html-to-text/-/html-to-text-1.4.31.tgz",
- "integrity": "sha512-9vTFw6vYZNnjPOep9WRXs7cw0vg04pAZgcX9bqx70q1BNT7y9sOJovpbiNIcSNyHF/6LscLvGhtb5Og1T0UEvA==",
- "dev": true
+ "version": "7946.0.8",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz",
+ "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA=="
},
"@types/http-errors": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.6.3.tgz",
- "integrity": "sha512-4KCE/agIcoQ9bIfa4sBxbZdnORzRjIw8JNQPLfqoNv7wQl/8f8mRbW68Q8wBsQFoJkPUHGlQYZ9sqi5WpfGSEQ==",
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.2.tgz",
+ "integrity": "sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w==",
"dev": true
},
"@types/json-schema": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz",
- "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==",
+ "version": "7.0.9",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
+ "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
"dev": true
},
"@types/lodash": {
- "version": "4.14.149",
- "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz",
- "integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==",
+ "version": "4.14.178",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz",
+ "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==",
"dev": true
},
+ "@types/mdast": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz",
+ "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "*"
+ }
+ },
"@types/mime": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz",
- "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==",
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
+ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
"dev": true
},
- "@types/minimatch": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
- "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA=="
- },
- "@types/mongodb": {
- "version": "3.5.4",
- "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.5.4.tgz",
- "integrity": "sha512-1Q781+rC+hYB34Ped9dRLOWsw1yTNwqphqkRyJR/yFuoWoZ3664s6RxilVSkqEm3lwFmpTYCXtGudxSpHHGDIQ==",
- "dev": true,
- "requires": {
- "@types/bson": "4.0.2",
- "@types/node": "12.12.32"
- }
+ "@types/ms": {
+ "version": "0.7.31",
+ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz",
+ "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA=="
},
"@types/node": {
- "version": "12.12.32",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.32.tgz",
- "integrity": "sha512-44/reuCrwiQEsXud3I5X3sqI5jIXAmHB5xoiyKUw965olNHF3IWKjBLKK3F9LOSUZmK+oDt8jmyO637iX+hMgA=="
+ "version": "16.11.59",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.59.tgz",
+ "integrity": "sha512-6u+36Dj3aDzhfBVUf/mfmc92OEdzQ2kx2jcXGdigfl70E/neV21ZHE6UCz4MDzTRcVqGAM27fk+DLXvyDsn3Jw=="
},
"@types/nodemailer": {
- "version": "6.4.0",
- "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.0.tgz",
- "integrity": "sha512-KY7bFWB0MahRZvVW4CuW83qcCDny59pJJ0MQ5ifvfcjNwPlIT0vW4uARO4u1gtkYnWdhSvURegecY/tzcukJcA==",
+ "version": "6.4.4",
+ "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.4.tgz",
+ "integrity": "sha512-Ksw4t7iliXeYGvIQcSIgWQ5BLuC/mljIEbjf615svhZL10PE9t+ei8O9gDaD3FPCasUJn9KTLwz2JFJyiiyuqw==",
"dev": true,
"requires": {
- "@types/node": "12.12.32"
+ "@types/node": "*"
}
},
+ "@types/qs": {
+ "version": "6.9.7",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
+ "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
+ "dev": true
+ },
"@types/range-parser": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
- "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
+ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
"dev": true
},
- "@types/sequelize": {
- "version": "4.28.8",
- "resolved": "https://registry.npmjs.org/@types/sequelize/-/sequelize-4.28.8.tgz",
- "integrity": "sha512-3n/iSpOtO5NynSBgEJ+738DK/ctxkqnVMvdPLZxrbZrf/rQgNm8wgDPDSarS1rmluvOe5ZMRDF8DXhts5MIbag==",
- "dev": true,
- "requires": {
- "@types/bluebird": "3.5.30",
- "@types/continuation-local-storage": "3.2.2",
- "@types/lodash": "4.14.149",
- "@types/validator": "12.0.1"
- }
- },
"@types/serve-static": {
- "version": "1.13.3",
- "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz",
- "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==",
+ "version": "1.13.10",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz",
+ "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
"dev": true,
"requires": {
- "@types/express-serve-static-core": "4.17.3",
- "@types/mime": "2.0.1"
- }
- },
- "@types/socket.io": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.4.tgz",
- "integrity": "sha512-cI98INy7tYnweTsUlp8ocveVdAxENUThO0JsLSCs51cjOP2yV5Mqo5QszMDPckyRRA+PO6+wBgKvGvHUCc23TQ==",
- "dev": true,
- "requires": {
- "@types/node": "12.12.32"
- }
- },
- "@types/tokgen": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@types/tokgen/-/tokgen-1.0.0.tgz",
- "integrity": "sha512-H1jyCXVxBrh2EfddtVJdgu9w65jaqBFYX0Tkm/rq7Sv1TYBURamJ3rE5C/+P9stsKj+Q/QQbQ5YXyY3SS6xG+g==",
- "dev": true
- },
- "@types/umzug": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/@types/umzug/-/umzug-2.2.3.tgz",
- "integrity": "sha512-mJ6xv5FR5KNa5yL4j3Q7/jLyzb3K5MMmqzUcQg/jekmvPH/g1/wraSMAu7JsEDWxXXgZcXw7rJgeZ6adWrvImg==",
- "dev": true,
- "requires": {
- "@types/mongodb": "3.5.4",
- "@types/sequelize": "4.28.8"
+ "@types/mime": "^1",
+ "@types/node": "*"
}
},
"@types/unist": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
- "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==",
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
+ "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
"dev": true
},
"@types/validator": {
- "version": "12.0.1",
- "resolved": "https://registry.npmjs.org/@types/validator/-/validator-12.0.1.tgz",
- "integrity": "sha512-l57fIANZLMe8DArz+SDb+7ATXnDm15P7u2wHBw5mb0aSMd+UuvmvhouBF2hdLgQPDMJ39sh9g2MJO4GkZ0VAdQ==",
+ "version": "13.7.1",
+ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.1.tgz",
+ "integrity": "sha512-I6OUIZ5cYRk5lp14xSOAiXjWrfVoMZVjDuevBYgQDYzZIjsf2CAISpEcXOkFAtpAHbmWIDLcZObejqny/9xq5Q=="
+ },
+ "@typescript-eslint/eslint-plugin": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz",
+ "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==",
+ "dev": true,
+ "requires": {
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "7.18.0",
+ "@typescript-eslint/type-utils": "7.18.0",
+ "@typescript-eslint/utils": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.3.1",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^1.3.0"
+ }
+ },
+ "@typescript-eslint/parser": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz",
+ "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/scope-manager": "7.18.0",
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/typescript-estree": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0",
+ "debug": "^4.3.4"
+ }
+ },
+ "@typescript-eslint/scope-manager": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz",
+ "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0"
+ }
+ },
+ "@typescript-eslint/type-utils": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz",
+ "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/typescript-estree": "7.18.0",
+ "@typescript-eslint/utils": "7.18.0",
+ "debug": "^4.3.4",
+ "ts-api-utils": "^1.3.0"
+ }
+ },
+ "@typescript-eslint/types": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz",
+ "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==",
+ "dev": true
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz",
+ "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "ts-api-utils": "^1.3.0"
+ },
+ "dependencies": {
+ "brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^2.0.1"
+ }
+ },
+ "semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true
+ }
+ }
+ },
+ "@typescript-eslint/utils": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz",
+ "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==",
+ "dev": true,
+ "requires": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "@typescript-eslint/scope-manager": "7.18.0",
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/typescript-estree": "7.18.0"
+ }
+ },
+ "@typescript-eslint/visitor-keys": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz",
+ "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "7.18.0",
+ "eslint-visitor-keys": "^3.4.3"
+ }
+ },
+ "@ungap/structured-clone": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
+ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
"dev": true
},
"abbrev": {
@@ -546,130 +6763,138 @@
"optional": true
},
"accepts": {
- "version": "1.3.7",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
- "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"requires": {
- "mime-types": "2.1.24",
- "negotiator": "0.6.2"
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ }
+ },
+ "acorn": {
+ "version": "8.12.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
+ "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
+ "dev": true
+ },
+ "acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "requires": {}
+ },
+ "agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "optional": true,
+ "requires": {
+ "debug": "4"
+ }
+ },
+ "agentkeepalive": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz",
+ "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==",
+ "optional": true,
+ "requires": {
+ "debug": "^4.1.0",
+ "depd": "^2.0.0",
+ "humanize-ms": "^1.2.1"
},
"dependencies": {
- "mime-db": {
- "version": "1.40.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
- "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
- },
- "mime-types": {
- "version": "2.1.24",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
- "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "optional": true
+ }
+ }
+ },
+ "aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "optional": true,
+ "requires": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ }
+ },
+ "ajv": {
+ "version": "7.2.4",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.4.tgz",
+ "integrity": "sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==",
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ajv-formats": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
+ "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
+ "requires": {
+ "ajv": "^8.0.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"requires": {
- "mime-db": "1.40.0"
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
}
}
}
},
- "acorn": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
- "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo="
- },
- "acorn-globals": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz",
- "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=",
- "requires": {
- "acorn": "4.0.13"
- },
- "dependencies": {
- "acorn": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
- "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c="
- }
- }
- },
- "after": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
- "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
- },
- "ajv": {
- "version": "6.12.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
- "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
- "requires": {
- "fast-deep-equal": "3.1.1",
- "fast-json-stable-stringify": "2.0.0",
- "json-schema-traverse": "0.4.1",
- "uri-js": "4.2.2"
- }
- },
- "align-text": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
- "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
- "requires": {
- "kind-of": "3.2.2",
- "longest": "1.0.1",
- "repeat-string": "1.6.1"
- }
- },
"ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "devOptional": true
},
"ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"requires": {
- "color-convert": "1.9.2"
+ "color-convert": "^2.0.1"
}
},
- "any-promise": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
- "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
- },
"aproba": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
- "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
+ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==",
"optional": true
},
"are-we-there-yet": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
- "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
+ "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
"optional": true,
"requires": {
- "delegates": "1.0.0",
- "readable-stream": "2.3.6"
+ "delegates": "^1.0.0",
+ "readable-stream": "^3.6.0"
}
},
+ "arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
"argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "requires": {
- "sprintf-js": "1.0.3"
- },
- "dependencies": {
- "sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
- "dev": true
- }
- }
- },
- "array-differ": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz",
- "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg=="
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
},
"array-flatten": {
"version": "1.1.1",
@@ -679,111 +6904,24 @@
"array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="
- },
- "arraybuffer.slice": {
- "version": "0.0.7",
- "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
- "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
- },
- "arrify": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
- "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="
- },
- "asap": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
- "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
- },
- "asn1": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
- "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
- },
- "assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true
},
"async": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
- "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw=="
- },
- "async-limiter": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
- "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
- },
- "asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
- },
- "aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
- },
- "aws4": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
- "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==",
- "optional": true
- },
- "babel-runtime": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
- "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "requires": {
- "core-js": "2.6.11",
- "regenerator-runtime": "0.11.1"
- },
- "dependencies": {
- "regenerator-runtime": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
- "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
- }
- }
- },
- "babel-types": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
- "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
- "requires": {
- "babel-runtime": "6.26.0",
- "esutils": "2.0.3",
- "lodash": "4.17.19",
- "to-fast-properties": "1.0.3"
- }
- },
- "babylon": {
- "version": "6.18.0",
- "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
- "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
- },
- "backo2": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
- "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
+ "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g=="
},
"bail": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
- "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
+ "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
"dev": true
},
"balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
- },
- "base64-arraybuffer": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
- "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"base64id": {
"version": "2.0.0",
@@ -798,357 +6936,217 @@
"safe-buffer": "5.1.2"
}
},
- "bcrypt-pbkdf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
- "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
- "optional": true,
- "requires": {
- "tweetnacl": "0.14.5"
- }
- },
- "better-assert": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
- "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
- "requires": {
- "callsite": "1.0.0"
- }
- },
"big.js": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
- "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.1.1.tgz",
+ "integrity": "sha512-1vObw81a8ylZO5ePrtMay0n018TcftpTA5HFKDaSuiUDBo8biRBtjIobw60OpwuvrGk+FsxKamqN4cnmj/eXdg==",
"dev": true
},
- "blob": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
- "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig=="
- },
- "bluebird": {
- "version": "3.7.2",
- "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
- "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
- },
"body-parser": {
- "version": "1.19.0",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
- "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "version": "1.20.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+ "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"requires": {
- "bytes": "3.1.0",
- "content-type": "1.0.4",
+ "bytes": "3.1.2",
+ "content-type": "~1.0.5",
"debug": "2.6.9",
- "depd": "1.1.2",
- "http-errors": "1.7.2",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
"iconv-lite": "0.4.24",
- "on-finished": "2.3.0",
- "qs": "6.7.0",
- "raw-body": "2.4.0",
- "type-is": "1.6.18"
+ "on-finished": "2.4.1",
+ "qs": "6.13.0",
+ "raw-body": "2.5.2",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
},
"dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
"http-errors": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
- "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"requires": {
- "depd": "1.1.2",
- "inherits": "2.0.3",
- "setprototypeof": "1.1.1",
- "statuses": "1.5.0",
- "toidentifier": "1.0.0"
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
}
},
- "iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "requires": {
- "safer-buffer": "2.1.2"
- }
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
- "qs": {
- "version": "6.7.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
- "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
}
}
},
- "boolbase": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
- "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
- },
- "boolean": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.0.tgz",
- "integrity": "sha512-OElxJ1lUSinuoUnkpOgLmxp0DC4ytEhODEL6QJU0NpxE/mI4rUSh8h1P1Wkvfi3xQEBcxXR2gBIPNYNuaFcAbQ=="
- },
"brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"requires": {
- "balanced-match": "1.0.0",
+ "balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
+ "braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "requires": {
+ "fill-range": "^7.1.1"
+ }
+ },
"buffer-writer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
"integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw=="
},
- "builtin-modules": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
- "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
- "dev": true
- },
"bytes": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
- "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
},
- "callsite": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
- "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
- },
- "camelcase": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
- "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk="
- },
- "caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
- },
- "ccount": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz",
- "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==",
- "dev": true
- },
- "center-align": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
- "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+ "cacache": {
+ "version": "15.3.0",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz",
+ "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==",
+ "optional": true,
"requires": {
- "align-text": "0.1.4",
- "lazy-cache": "1.0.4"
+ "@npmcli/fs": "^1.0.0",
+ "@npmcli/move-file": "^1.0.1",
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "glob": "^7.1.4",
+ "infer-owner": "^1.0.4",
+ "lru-cache": "^6.0.0",
+ "minipass": "^3.1.1",
+ "minipass-collect": "^1.0.2",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.2",
+ "mkdirp": "^1.0.3",
+ "p-map": "^4.0.0",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^3.0.2",
+ "ssri": "^8.0.1",
+ "tar": "^6.0.2",
+ "unique-filename": "^1.1.1"
}
},
- "centra": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/centra/-/centra-2.4.0.tgz",
- "integrity": "sha512-AWmF3EHNe/noJHviynZOrdnUuQzT5AMgl9nJPXGvnzGXrI2ZvNDrEcdqskc4EtQwt2Q1IggXb0OXy7zZ1Xvvew==",
+ "call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "requires": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ }
+ },
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true
},
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "ccount": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
+ "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==",
+ "dev": true
+ },
+ "centra": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz",
+ "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==",
+ "dev": true,
"requires": {
- "ansi-styles": "3.2.1",
- "escape-string-regexp": "1.0.5",
- "supports-color": "5.5.0"
+ "follow-redirects": "^1.15.6"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
}
},
"character-entities": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
- "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.1.tgz",
+ "integrity": "sha512-OzmutCf2Kmc+6DrFrrPS8/tDh2+DpnrfzdICHWhcVC9eOd0N1PXmQEE1a8iM4IziIAG+8tmTq3K+oo0ubH6RRQ==",
"dev": true
},
- "character-entities-html4": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
- "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==",
- "dev": true
- },
- "character-entities-legacy": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
- "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
- "dev": true
- },
- "character-parser": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz",
- "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=",
- "requires": {
- "is-regex": "1.0.5"
- }
- },
- "character-reference-invalid": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
- "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
- "dev": true
- },
- "cheerio": {
- "version": "0.22.0",
- "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz",
- "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=",
- "requires": {
- "css-select": "1.2.0",
- "dom-serializer": "0.1.1",
- "entities": "1.1.2",
- "htmlparser2": "3.10.1",
- "lodash.assignin": "4.2.0",
- "lodash.bind": "4.2.1",
- "lodash.defaults": "4.2.0",
- "lodash.filter": "4.6.0",
- "lodash.flatten": "4.4.0",
- "lodash.foreach": "4.5.0",
- "lodash.map": "4.6.0",
- "lodash.merge": "4.6.2",
- "lodash.pick": "4.4.0",
- "lodash.reduce": "4.6.0",
- "lodash.reject": "4.6.0",
- "lodash.some": "4.6.0"
- },
- "dependencies": {
- "dom-serializer": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
- "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
- "requires": {
- "domelementtype": "1.3.1",
- "entities": "1.1.2"
- }
- }
- }
- },
"chownr": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
- "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
"optional": true
},
- "clean-css": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
- "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==",
- "requires": {
- "source-map": "0.6.1"
- }
+ "clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "optional": true
},
"cliui": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
- "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true,
"requires": {
- "string-width": "3.1.0",
- "strip-ansi": "5.2.0",
- "wrap-ansi": "5.1.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
- "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
- "dev": true
- },
- "string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
- "dev": true,
- "requires": {
- "emoji-regex": "7.0.3",
- "is-fullwidth-code-point": "2.0.0",
- "strip-ansi": "5.2.0"
- }
- },
- "strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "dev": true,
- "requires": {
- "ansi-regex": "4.1.0"
- }
- }
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
}
},
- "cls-bluebird": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz",
- "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=",
- "requires": {
- "is-bluebird": "1.0.2",
- "shimmer": "1.2.1"
- }
- },
- "co": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
- "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
- "optional": true
- },
- "code-point-at": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
- },
- "collapse-white-space": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
- "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==",
- "dev": true
- },
"color-convert": {
- "version": "1.9.2",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
- "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
- "color-name": "1.1.1"
+ "color-name": "~1.1.4"
}
},
"color-name": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
- "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok="
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "color-support": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+ "optional": true
},
"colorette": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.1.0.tgz",
- "integrity": "sha512-6S062WDQUXi6hOfkO/sBPVwE5ASXY4G2+b4atvhJfSsuUUhIaUKlkjLe9692Ipyt5/a+IPF5aVTu3V5gvXq5cg==",
+ "version": "2.0.16",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz",
+ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==",
"dev": true
},
- "combined-stream": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
- "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
- "requires": {
- "delayed-stream": "1.0.0"
- }
- },
- "commander": {
- "version": "2.20.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
- "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
- },
- "component-bind": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
- "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
- },
- "component-inherit": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
- "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
- },
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -1157,183 +7155,135 @@
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
- "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
- },
- "consolidate": {
- "version": "0.15.1",
- "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz",
- "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==",
- "requires": {
- "bluebird": "3.7.2"
- }
- },
- "constantinople": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz",
- "integrity": "sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw==",
- "requires": {
- "@types/babel-types": "7.0.7",
- "@types/babylon": "6.16.5",
- "babel-types": "6.26.0",
- "babylon": "6.18.0"
- }
+ "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
+ "optional": true
},
"content-disposition": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
- "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"requires": {
- "safe-buffer": "5.1.2"
+ "safe-buffer": "5.2.1"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ }
}
},
"content-type": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
- "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
},
"cookie": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
- "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
+ "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
- "core-js": {
- "version": "2.6.11",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz",
- "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg=="
- },
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
- },
- "country-language": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/country-language/-/country-language-0.1.7.tgz",
- "integrity": "sha1-eHD0uhJduaYHHxlze9nvk0OuNds=",
+ "cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"requires": {
- "underscore": "1.7.0",
- "underscore.deep": "0.5.1"
+ "object-assign": "^4",
+ "vary": "^1"
}
},
+ "create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true
+ },
"cross-spawn": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
- "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
"requires": {
- "nice-try": "1.0.5",
- "path-key": "2.0.1",
- "semver": "5.5.0",
- "shebang-command": "1.2.0",
- "which": "1.3.1"
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
}
},
- "crypto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
- "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig=="
- },
- "css-select": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
- "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
- "requires": {
- "boolbase": "1.0.0",
- "css-what": "2.1.3",
- "domutils": "1.5.1",
- "nth-check": "1.0.2"
- },
- "dependencies": {
- "domutils": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
- "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
- "requires": {
- "dom-serializer": "0.2.2",
- "domelementtype": "1.3.1"
- }
- }
- }
- },
- "css-what": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
- "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg=="
- },
- "dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
- "requires": {
- "assert-plus": "1.0.0"
- }
- },
- "datauri": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/datauri/-/datauri-2.0.0.tgz",
- "integrity": "sha512-zS2HSf9pI5XPlNZgIqJg/wCJpecgU/HA6E/uv2EfaWnW1EiTGLfy/EexTIsC9c99yoCOTXlqeeWk4FkCSuO3/g==",
- "requires": {
- "image-size": "0.7.5",
- "mimer": "1.0.0"
- }
- },
- "dayjs": {
- "version": "1.8.23",
- "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.23.tgz",
- "integrity": "sha512-NmYHMFONftoZbeOhVz6jfiXI4zSiPN6NoVWJgC0aZQfYVwzy/ZpESPHuCcI0B8BUMpSJQ08zenHDbofOLKq8hQ=="
+ "cuint": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz",
+ "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=",
+ "dev": true
},
"debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+ "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"requires": {
- "ms": "2.0.0"
+ "ms": "2.1.2"
}
},
- "decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+ "decode-named-character-reference": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.1.tgz",
+ "integrity": "sha512-YV/0HQHreRwKb7uBopyIkLG17jG6Sv2qUchk9qSoVJ2f+flwRsPNBO0hAnjt6mTNYUT+vw9Gy2ihXg4sUWPi2w==",
+ "dev": true,
+ "requires": {
+ "character-entities": "^2.0.0"
+ }
},
- "deep-extend": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
- "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+ "deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true
},
- "delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ "define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "requires": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ }
},
"delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
- "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
"optional": true
},
"denque": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz",
- "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ=="
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
+ "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw=="
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
+ "dequal": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
+ "integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==",
+ "dev": true
+ },
"destroy": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
- "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
},
"detect-libc": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
- "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
+ "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
"optional": true
},
"diff": {
@@ -1342,257 +7292,136 @@
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
- "doctrine": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz",
- "integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=",
+ "dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
"dev": true,
"requires": {
- "esutils": "1.1.6",
- "isarray": "0.0.1"
- },
- "dependencies": {
- "esutils": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz",
- "integrity": "sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=",
- "dev": true
- },
- "isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
- "dev": true
- }
+ "path-type": "^4.0.0"
}
},
- "doctypes": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz",
- "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk="
- },
- "dom-serializer": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
- "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+ "doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
"requires": {
- "domelementtype": "2.0.1",
- "entities": "2.0.0"
- },
- "dependencies": {
- "domelementtype": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
- "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
- },
- "entities": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
- "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
- }
- }
- },
- "domelementtype": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
- "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
- },
- "domhandler": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
- "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
- "requires": {
- "domelementtype": "1.3.1"
- }
- },
- "domutils": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
- "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
- "requires": {
- "dom-serializer": "0.2.2",
- "domelementtype": "1.3.1"
+ "esutils": "^2.0.2"
}
},
"dottie": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz",
- "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg=="
- },
- "ecc-jsbn": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
- "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
- "optional": true,
- "requires": {
- "jsbn": "0.1.1",
- "safer-buffer": "2.1.2"
- }
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz",
+ "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA=="
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"ejs": {
- "version": "2.7.4",
- "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz",
- "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA=="
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
+ "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
+ "requires": {
+ "jake": "^10.8.5"
+ }
},
"email-addresses": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
"integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg=="
},
- "email-templates": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/email-templates/-/email-templates-7.0.4.tgz",
- "integrity": "sha512-+s8Eav1XCF6IveHXK4lWxXdMm3XCk9eDIMX0p9simqIPW1gzR4haMpNhID2pZBQzDyY0yylW74IMB9+3Ntwjmw==",
- "requires": {
- "@ladjs/i18n": "3.0.4",
- "@sindresorhus/is": "2.1.0",
- "consolidate": "0.15.1",
- "debug": "4.1.1",
- "get-paths": "0.0.7",
- "html-to-text": "5.1.1",
- "juice": "6.0.0",
- "lodash": "4.17.19",
- "nodemailer": "6.4.6",
- "pify": "5.0.0",
- "preview-email": "2.0.1"
- },
- "dependencies": {
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "pify": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz",
- "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA=="
- }
- }
+ "emittery": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
+ "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ=="
},
"emoji-regex": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
- "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
- "dev": true
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "devOptional": true
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
},
- "encoding-japanese": {
- "version": "1.0.30",
- "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-1.0.30.tgz",
- "integrity": "sha512-bd/DFLAoJetvv7ar/KIpE3CNO8wEuyrt9Xuw6nSMiZ+Vrz/Q21BPsMHvARL2Wz6IKHKXgb+DWZqtRg1vql9cBg=="
- },
- "engine.io": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.0.tgz",
- "integrity": "sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==",
+ "encoding": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+ "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+ "optional": true,
"requires": {
- "accepts": "1.3.7",
- "base64id": "2.0.0",
- "cookie": "0.3.1",
- "debug": "4.1.1",
- "engine.io-parser": "2.2.0",
- "ws": "7.2.0"
+ "iconv-lite": "^0.6.2"
},
"dependencies": {
- "cookie": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
- "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
- },
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "optional": true,
"requires": {
- "ms": "2.1.2"
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
}
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
- "engine.io-client": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.0.tgz",
- "integrity": "sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==",
+ "engine.io": {
+ "version": "6.6.2",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz",
+ "integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==",
"requires": {
- "component-emitter": "1.2.1",
- "component-inherit": "0.0.3",
- "debug": "4.1.1",
- "engine.io-parser": "2.2.0",
- "has-cors": "1.1.0",
- "indexof": "0.0.1",
- "parseqs": "0.0.5",
- "parseuri": "0.0.5",
- "ws": "6.1.4",
- "xmlhttprequest-ssl": "1.5.5",
- "yeast": "0.1.2"
+ "@types/cookie": "^0.4.1",
+ "@types/cors": "^2.8.12",
+ "@types/node": ">=10.0.0",
+ "accepts": "~1.3.4",
+ "base64id": "2.0.0",
+ "cookie": "~0.7.2",
+ "cors": "~2.8.5",
+ "debug": "~4.3.1",
+ "engine.io-parser": "~5.2.1",
+ "ws": "~8.17.1"
},
"dependencies": {
- "component-emitter": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
- "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
- },
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "ws": {
- "version": "6.1.4",
- "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
- "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
- "requires": {
- "async-limiter": "1.0.1"
- }
+ "cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="
}
}
},
"engine.io-parser": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz",
- "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==",
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
+ "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="
+ },
+ "env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "optional": true
+ },
+ "err-code": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
+ "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
+ "optional": true
+ },
+ "es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
"requires": {
- "after": "0.8.2",
- "arraybuffer.slice": "0.0.7",
- "base64-arraybuffer": "0.1.5",
- "blob": "0.0.5",
- "has-binary2": "1.0.3"
+ "get-intrinsic": "^1.2.4"
}
},
- "entities": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
- "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
+ "es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="
},
"es2015-i18n-tag": {
"version": "1.6.1",
@@ -1600,205 +7429,463 @@
"integrity": "sha512-MYoh9p+JTkgnzBh0MEBON6xUyzdmwT6wzsmmFJvZujGSXiI2kM+3XvFl6+AcIO2eeL6VWgtX9szSiDTMwDxyYA==",
"dev": true
},
+ "escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true
+ },
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
},
"escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true
},
- "esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "eslint": {
+ "version": "8.57.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
+ "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+ "dev": true,
+ "requires": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.57.0",
+ "@humanwhocodes/config-array": "^0.11.14",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3",
+ "strip-ansi": "^6.0.1",
+ "text-table": "^0.2.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ }
+ }
+ },
+ "eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true
+ },
+ "espree": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "dev": true,
+ "requires": {
+ "acorn": "^8.9.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ }
+ },
+ "esquery": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+ "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.1.0"
+ }
+ },
+ "esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.2.0"
+ }
+ },
+ "estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true
},
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
- },
- "expand-string": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/expand-string/-/expand-string-1.1.1.tgz",
- "integrity": "sha1-fBHCis10tezZkluPKezSeT+HFU4=",
- "requires": {
- "lodash.defaults": "4.2.0"
- }
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
},
"express": {
- "version": "4.17.1",
- "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
- "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+ "version": "4.21.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+ "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"requires": {
- "accepts": "1.3.7",
+ "accepts": "~1.3.8",
"array-flatten": "1.1.1",
- "body-parser": "1.19.0",
- "content-disposition": "0.5.3",
- "content-type": "1.0.4",
- "cookie": "0.4.0",
+ "body-parser": "1.20.3",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.7.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
- "depd": "1.1.2",
- "encodeurl": "1.0.2",
- "escape-html": "1.0.3",
- "etag": "1.8.1",
- "finalhandler": "1.1.2",
+ "depd": "2.0.0",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.3.1",
"fresh": "0.5.2",
- "merge-descriptors": "1.0.1",
- "methods": "1.1.2",
- "on-finished": "2.3.0",
- "parseurl": "1.3.3",
- "path-to-regexp": "0.1.7",
- "proxy-addr": "2.0.5",
- "qs": "6.7.0",
- "range-parser": "1.2.1",
- "safe-buffer": "5.1.2",
- "send": "0.17.1",
- "serve-static": "1.14.1",
- "setprototypeof": "1.1.1",
- "statuses": "1.5.0",
- "type-is": "1.6.18",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.3",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.12",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.13.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.19.0",
+ "serve-static": "1.16.2",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
"utils-merge": "1.0.1",
- "vary": "1.1.2"
+ "vary": "~1.1.2"
},
"dependencies": {
- "qs": {
- "version": "6.7.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
- "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
+ "encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="
+ },
+ "http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "requires": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ },
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
}
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
- },
- "extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
},
"fast-deep-equal": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
- "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "requires": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "dependencies": {
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ }
+ }
},
"fast-json-stable-stringify": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
- "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
+ },
+ "fast-uri": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz",
+ "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw=="
+ },
+ "fastestsmallesttextencoderdecoder": {
+ "version": "1.0.22",
+ "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz",
+ "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==",
+ "dev": true
+ },
+ "fastq": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
+ "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
+ "requires": {
+ "reusify": "^1.0.4"
+ }
},
"ferrum": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/ferrum/-/ferrum-1.7.0.tgz",
- "integrity": "sha512-Ycr5nz/Pj7HsIqx+dZgAq27nq35bSzNzwsUbc4vFPl9PG1OgrzwDH57noH6blT7gh1XzKnqEYGrSYDU+4Vy2VA==",
+ "version": "1.9.4",
+ "resolved": "https://registry.npmjs.org/ferrum/-/ferrum-1.9.4.tgz",
+ "integrity": "sha512-ooNerLoIht/dK4CQJux93z/hnt9JysrXniJCI3r6YRgmHeXC57EJ8XaTCT1Gm8LfhIAeWxyJA0O7d/W3pqDYRg==",
"dev": true,
"requires": {
- "lodash.isplainobject": "4.0.6"
+ "fastestsmallesttextencoderdecoder": "1.0.22",
+ "lodash.isplainobject": "4.0.6",
+ "xxhashjs": "0.2.2"
+ }
+ },
+ "file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^3.0.4"
+ }
+ },
+ "filelist": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
+ "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "requires": {
+ "to-regex-range": "^5.0.1"
}
},
"finalhandler": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
- "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+ "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"requires": {
"debug": "2.6.9",
- "encodeurl": "1.0.2",
- "escape-html": "1.0.3",
- "on-finished": "2.3.0",
- "parseurl": "1.3.3",
- "statuses": "1.5.0",
- "unpipe": "1.0.0"
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+ }
}
},
"find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"requires": {
- "locate-path": "3.0.0"
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
}
},
- "forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
- },
- "form-data": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
- "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
+ "flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
"requires": {
- "asynckit": "0.4.0",
- "combined-stream": "1.0.6",
- "mime-types": "2.1.19"
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
}
},
+ "flatted": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz",
+ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==",
+ "dev": true
+ },
+ "follow-redirects": {
+ "version": "1.15.6",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
+ "dev": true
+ },
"forwarded": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
- "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
},
"fs-extra": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
- "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
+ "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
"dev": true,
"requires": {
- "graceful-fs": "4.2.3",
- "jsonfile": "4.0.0",
- "universalify": "0.1.2"
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
}
},
"fs-minipass": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
- "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
"optional": true,
"requires": {
- "minipass": "2.3.5"
+ "minipass": "^3.0.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "devOptional": true
},
"function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
},
"gauge": {
- "version": "2.7.4",
- "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
- "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
+ "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
"optional": true,
"requires": {
- "aproba": "1.2.0",
- "console-control-strings": "1.1.0",
- "has-unicode": "2.0.1",
- "object-assign": "4.1.1",
- "signal-exit": "3.0.2",
- "string-width": "1.0.2",
- "strip-ansi": "3.0.1",
- "wide-align": "1.1.3"
+ "aproba": "^1.0.3 || ^2.0.0",
+ "color-support": "^1.1.2",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.1",
+ "object-assign": "^4.1.1",
+ "signal-exit": "^3.0.0",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1",
+ "wide-align": "^1.1.2"
}
},
"get-caller-file": {
@@ -1807,635 +7894,410 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
- "get-paths": {
- "version": "0.0.7",
- "resolved": "https://registry.npmjs.org/get-paths/-/get-paths-0.0.7.tgz",
- "integrity": "sha512-0wdJt7C1XKQxuCgouqd+ZvLJ56FQixKoki9MrFaO4EriqzXOiH9gbukaDE1ou08S8Ns3/yDzoBAISNPqj6e6tA==",
+ "get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"requires": {
- "pify": "4.0.1"
- },
- "dependencies": {
- "pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
- }
- }
- },
- "getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
- "requires": {
- "assert-plus": "1.0.0"
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
}
},
"github-slugger": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.3.0.tgz",
- "integrity": "sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q==",
- "dev": true,
- "requires": {
- "emoji-regex": "6.1.1"
- },
- "dependencies": {
- "emoji-regex": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.1.tgz",
- "integrity": "sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4=",
- "dev": true
- }
- }
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz",
+ "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==",
+ "dev": true
},
"glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "devOptional": true,
"requires": {
- "fs.realpath": "1.0.0",
- "inflight": "1.0.6",
- "inherits": "2.0.3",
- "minimatch": "3.0.4",
- "once": "1.4.0",
- "path-is-absolute": "1.0.1"
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.3"
+ }
+ },
+ "globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.20.2"
+ }
+ },
+ "globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "requires": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ }
+ },
+ "gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "requires": {
+ "get-intrinsic": "^1.1.3"
}
},
"graceful-fs": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
- "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
+ "version": "4.2.9",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
+ "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
+ },
+ "graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
"dev": true
},
- "har-schema": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
- },
- "har-validator": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
- "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
- "optional": true,
- "requires": {
- "ajv": "5.5.2",
- "har-schema": "2.0.0"
- },
- "dependencies": {
- "ajv": {
- "version": "5.5.2",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
- "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
- "optional": true,
- "requires": {
- "co": "4.6.0",
- "fast-deep-equal": "1.1.0",
- "fast-json-stable-stringify": "2.0.0",
- "json-schema-traverse": "0.3.1"
- }
- },
- "fast-deep-equal": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
- "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
- "optional": true
- },
- "json-schema-traverse": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
- "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
- "optional": true
- }
- }
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "requires": {
- "function-bind": "1.1.1"
- }
- },
- "has-binary2": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
- "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
- "requires": {
- "isarray": "2.0.1"
- },
- "dependencies": {
- "isarray": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
- "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
- }
- }
- },
- "has-cors": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
- "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
- },
"has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+ },
+ "has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "requires": {
+ "es-define-property": "^1.0.0"
+ }
+ },
+ "has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q=="
+ },
+ "has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
},
"has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
- "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
"optional": true
},
- "he": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
- "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
- },
- "html-to-text": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-5.1.1.tgz",
- "integrity": "sha512-Bci6bD/JIfZSvG4s0gW/9mMKwBRoe/1RWLxUME/d6WUSZCdY7T60bssf/jFf7EYXRyqU4P5xdClVqiYU0/ypdA==",
+ "hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"requires": {
- "he": "1.2.0",
- "htmlparser2": "3.10.1",
- "lodash": "4.17.19",
- "minimist": "1.2.5"
- },
- "dependencies": {
- "minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
- }
+ "function-bind": "^1.1.2"
}
},
- "htmlparser2": {
- "version": "3.10.1",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
- "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
- "requires": {
- "domelementtype": "1.3.1",
- "domhandler": "2.4.2",
- "domutils": "1.7.0",
- "entities": "1.1.2",
- "inherits": "2.0.3",
- "readable-stream": "3.6.0"
- },
- "dependencies": {
- "readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
- "requires": {
- "inherits": "2.0.3",
- "string_decoder": "1.1.1",
- "util-deprecate": "1.0.2"
- }
- }
- }
+ "http-cache-semantics": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
+ "optional": true
},
"http-errors": {
- "version": "1.7.3",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
- "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
+ "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"requires": {
- "depd": "1.1.2",
+ "depd": "~1.1.2",
"inherits": "2.0.4",
- "setprototypeof": "1.1.1",
- "statuses": "1.5.0",
- "toidentifier": "1.0.0"
- },
- "dependencies": {
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- }
+ "setprototypeof": "1.2.0",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.1"
}
},
- "http-signature": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
- "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "http-proxy-agent": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+ "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+ "optional": true,
"requires": {
- "assert-plus": "1.0.0",
- "jsprim": "1.4.1",
- "sshpk": "1.14.2"
+ "@tootallnate/once": "1",
+ "agent-base": "6",
+ "debug": "4"
}
},
- "i18n": {
- "version": "0.8.6",
- "resolved": "https://registry.npmjs.org/i18n/-/i18n-0.8.6.tgz",
- "integrity": "sha512-aMsJq8i1XXrb+BBsgmJBwak9mr69zPEIAUPb6c5yw2G/O4k1Q52lBxL+agZdQDN/RGf1ylQzrCswsOOgIiC1FA==",
+ "https-proxy-agent": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "optional": true,
"requires": {
- "debug": "2.6.9",
- "make-plural": "6.1.0",
- "math-interval-parser": "2.0.1",
- "messageformat": "2.3.0",
- "mustache": "4.0.1",
- "sprintf-js": "1.1.2"
+ "agent-base": "6",
+ "debug": "4"
}
},
- "i18n-locales": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/i18n-locales/-/i18n-locales-0.0.4.tgz",
- "integrity": "sha512-aP6VjhoBwSC8uZUehHWSszqdeWiheNXp0+oLPcZY4QAktsqcouHNYQee2NQFM4KNcCTKHHbfXrRUuOxjxF2jYw==",
+ "humanize-ms": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+ "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+ "optional": true,
"requires": {
- "country-language": "0.1.7"
- }
- },
- "iab_verifier": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/iab_verifier/-/iab_verifier-0.1.2.tgz",
- "integrity": "sha1-2t5VDuOJu96FaLL0ynHV0RFQCV4=",
- "requires": {
- "crypto": "1.0.1"
+ "ms": "^2.0.0"
}
},
"iconv-lite": {
- "version": "0.4.23",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
- "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
- "optional": true,
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
- "safer-buffer": "2.1.2"
+ "safer-buffer": ">= 2.1.2 < 3"
}
},
- "ignore-walk": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
- "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
- "optional": true,
+ "ignore": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
+ "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
+ "dev": true
+ },
+ "import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
"requires": {
- "minimatch": "3.0.4"
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
}
},
- "image-size": {
- "version": "0.7.5",
- "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz",
- "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g=="
+ "import-lazy": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
+ "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw=="
},
- "indexof": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
- "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "devOptional": true
+ },
+ "indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "optional": true
+ },
+ "infer-owner": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
+ "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
+ "optional": true
},
"inflection": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz",
- "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY="
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz",
+ "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw=="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "devOptional": true,
"requires": {
- "once": "1.4.0",
- "wrappy": "1.0.2"
+ "once": "^1.3.0",
+ "wrappy": "1"
}
},
"inherits": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
- "ini": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
- "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
- "optional": true
+ "ip-address": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
+ "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
+ "optional": true,
+ "requires": {
+ "jsbn": "1.1.0",
+ "sprintf-js": "^1.1.3"
+ }
},
"ipaddr.js": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
- "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
- },
- "is-alphabetical": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
- "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
- "dev": true
- },
- "is-alphanumeric": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz",
- "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=",
- "dev": true
- },
- "is-alphanumerical": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
- "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
- "dev": true,
- "requires": {
- "is-alphabetical": "1.0.4",
- "is-decimal": "1.0.4"
- }
- },
- "is-bluebird": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz",
- "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI="
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
"is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "is-decimal": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
- "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+ "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
"dev": true
},
- "is-empty": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/is-empty/-/is-empty-1.2.0.tgz",
- "integrity": "sha1-3pu1snhzigWgsJpX4ftNSjQan2s=",
- "dev": true
- },
- "is-expression": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz",
- "integrity": "sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=",
+ "is-core-module": {
+ "version": "2.15.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz",
+ "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==",
"requires": {
- "acorn": "4.0.13",
- "object-assign": "4.1.1"
- },
- "dependencies": {
- "acorn": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
- "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c="
- }
+ "hasown": "^2.0.2"
}
},
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ },
"is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "devOptional": true
+ },
+ "is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"requires": {
- "number-is-nan": "1.0.1"
+ "is-extglob": "^2.1.1"
}
},
- "is-hexadecimal": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
- "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
+ "is-lambda": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
+ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
+ "optional": true
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
+ },
+ "is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
"dev": true
},
"is-plain-obj": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
- "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.0.0.tgz",
+ "integrity": "sha512-NXRbBtUdBioI73y/HmOhogw/U5msYPC9DAtGkJXeFcFWSFZw0mCUsPxk/snTuJHzNKA8kLBK4rH97RMB1BfCXw==",
"dev": true
},
- "is-promise": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
- "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
- },
- "is-regex": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
- "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
- "requires": {
- "has": "1.0.3"
- }
- },
- "is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
- },
- "is-whitespace-character": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
- "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
- "dev": true
- },
- "is-word-character": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
- "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==",
- "dev": true
- },
- "is-wsl": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
- "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
- },
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
- },
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "devOptional": true
},
- "isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ "jake": {
+ "version": "10.8.5",
+ "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
+ "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==",
+ "requires": {
+ "async": "^3.2.3",
+ "chalk": "^4.0.2",
+ "filelist": "^1.0.1",
+ "minimatch": "^3.0.4"
+ }
},
- "js-stringify": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz",
- "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds="
+ "jju": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
+ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA=="
},
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
+ "jose": {
+ "version": "4.15.5",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz",
+ "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg=="
},
"js-yaml": {
- "version": "3.13.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
- "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"requires": {
- "argparse": "1.0.10",
- "esprima": "4.0.1"
+ "argparse": "^2.0.1"
}
},
"jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
+ "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
"optional": true
},
"json-schema": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
- "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
- },
- "json-stable-stringify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
- "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
- "dev": true,
- "requires": {
- "jsonify": "0.0.0"
- }
- },
- "json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
- },
- "jsonfile": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
- "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
- "dev": true,
- "requires": {
- "graceful-fs": "4.2.3"
- }
- },
- "jsonify": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
- "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
"dev": true
},
- "jsprim": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
- "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
- "requires": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.2.3",
- "verror": "1.10.0"
- }
- },
- "jstransformer": {
+ "json-schema-traverse": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz",
- "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
+ "jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
"requires": {
- "is-promise": "2.1.0",
- "promise": "7.3.1"
+ "graceful-fs": "^4.1.6",
+ "universalify": "^2.0.0"
}
},
- "juice": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/juice/-/juice-6.0.0.tgz",
- "integrity": "sha512-5T3JPgXYiw6A6axsb9E09Gzq46WbfJeDirY6nMrqY55iAdqEoPDxSr1GpXqYfoyndx4ujpBPXGLzBRzbiqOOaw==",
+ "kleur": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz",
+ "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==",
+ "dev": true
+ },
+ "levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
"requires": {
- "cheerio": "0.22.0",
- "commander": "2.20.0",
- "cross-spawn": "6.0.5",
- "deep-extend": "0.6.0",
- "mensch": "0.3.4",
- "slick": "1.12.2",
- "web-resource-inliner": "4.3.4"
- }
- },
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "1.1.6"
- }
- },
- "lazy-cache": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
- "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4="
- },
- "libbase64": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.2.1.tgz",
- "integrity": "sha512-l+nePcPbIG1fNlqMzrh68MLkX/gTxk/+vdvAb388Ssi7UuUN31MI44w4Yf33mM3Cm4xDfw48mdf3rkdHszLNew=="
- },
- "libmime": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/libmime/-/libmime-4.2.1.tgz",
- "integrity": "sha512-09y7zjSc5im1aNsq815zgo4/G3DnIzym3aDOHsGq4Ee5vrX4PdgQRybAsztz9Rv0NhO+J5C0llEUloa3sUmjmA==",
- "requires": {
- "encoding-japanese": "1.0.30",
- "iconv-lite": "0.5.0",
- "libbase64": "1.2.1",
- "libqp": "1.1.0"
- },
- "dependencies": {
- "iconv-lite": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.0.tgz",
- "integrity": "sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw==",
- "requires": {
- "safer-buffer": "2.1.2"
- }
- }
- }
- },
- "libqp": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz",
- "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g="
- },
- "linkify-it": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
- "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
- "requires": {
- "uc.micro": "1.0.6"
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
}
},
"locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"requires": {
- "p-locate": "3.0.0",
- "path-exists": "3.0.0"
+ "p-locate": "^5.0.0"
}
},
"lodash": {
- "version": "4.17.19",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
- "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
- },
- "lodash.assignin": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz",
- "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI="
- },
- "lodash.bind": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz",
- "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU="
- },
- "lodash.defaults": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
- "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
- },
- "lodash.filter": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz",
- "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4="
- },
- "lodash.flatten": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
- "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8="
- },
- "lodash.foreach": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
- "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM="
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash.isplainobject": {
"version": "4.0.6",
@@ -2443,174 +8305,258 @@
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
"dev": true
},
- "lodash.map": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
- "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM="
- },
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
- },
- "lodash.pick": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
- "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM="
- },
- "lodash.reduce": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
- "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs="
- },
- "lodash.reject": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz",
- "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU="
- },
- "lodash.some": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz",
- "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0="
- },
- "lodash.unescape": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz",
- "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw="
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
},
"long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
- "longest": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
- "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc="
- },
"longest-streak": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz",
- "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.0.1.tgz",
+ "integrity": "sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg==",
"dev": true
},
- "mailparser": {
- "version": "2.7.7",
- "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-2.7.7.tgz",
- "integrity": "sha512-FcVkXYm+zIg59HNPINGQw99eMTvcAkmQZHmabF8aSeMZ6/vWkx0HdT6FpXApelfe5IKRk6nWEg+YAuuXZl9+Fg==",
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
- "encoding-japanese": "1.0.30",
- "he": "1.2.0",
- "html-to-text": "5.1.1",
- "iconv-lite": "0.5.0",
- "libmime": "4.2.1",
- "linkify-it": "2.2.0",
- "mailsplit": "4.6.2",
- "nodemailer": "6.4.0",
- "tlds": "1.207.0"
+ "yallist": "^4.0.0"
+ }
+ },
+ "make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "optional": true,
+ "requires": {
+ "semver": "^6.0.0"
},
"dependencies": {
- "iconv-lite": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.0.tgz",
- "integrity": "sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw==",
- "requires": {
- "safer-buffer": "2.1.2"
- }
- },
- "nodemailer": {
- "version": "6.4.0",
- "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.0.tgz",
- "integrity": "sha512-UBqPOfQGD1cM3HnjhuQe+0u3DWx47WWK7lBjG5UtPnGOysr7oDK5lNCzcjK6zzeBSdTk4m1tGx1xNbWFZQmMNA=="
+ "semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "optional": true
}
}
},
- "mailsplit": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-4.6.2.tgz",
- "integrity": "sha512-7Bw2R0QfORXexGGQCEK64EeShHacUNyU5kV5F5sj4jPQB3ITe2v9KRqxD40wpuue6W/sBJlSNBZ0AypIeTGQMQ==",
- "requires": {
- "libbase64": "1.2.1",
- "libmime": "4.2.1",
- "libqp": "1.1.0"
- }
+ "make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
},
- "make-plural": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-6.1.0.tgz",
- "integrity": "sha512-0ekbPHqxcdRcmjZ43TkRuejK5rXgMF1OjG4FVnVHgCvOcjrexaSX7a0dfAvqhOm1qWPgjYnXtmz3cHpHW5ZewA=="
+ "make-fetch-happen": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz",
+ "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==",
+ "optional": true,
+ "requires": {
+ "agentkeepalive": "^4.1.3",
+ "cacache": "^15.2.0",
+ "http-cache-semantics": "^4.1.0",
+ "http-proxy-agent": "^4.0.1",
+ "https-proxy-agent": "^5.0.0",
+ "is-lambda": "^1.0.1",
+ "lru-cache": "^6.0.0",
+ "minipass": "^3.1.3",
+ "minipass-collect": "^1.0.2",
+ "minipass-fetch": "^1.3.2",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.4",
+ "negotiator": "^0.6.2",
+ "promise-retry": "^2.0.1",
+ "socks-proxy-agent": "^6.0.0",
+ "ssri": "^8.0.0"
+ }
},
"mariadb": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/mariadb/-/mariadb-2.3.1.tgz",
- "integrity": "sha512-suv+ygoiS+tQSKmxgzJsGV9R+USN8g6Ql+GuMo9k7alD6FxOT/lwebLHy63/7yPZfVtlyAitK1tPd7ZoFhN/Sg==",
+ "version": "2.5.5",
+ "resolved": "https://registry.npmjs.org/mariadb/-/mariadb-2.5.5.tgz",
+ "integrity": "sha512-6dklvcKWuuaV1JjAwnE2ezR+jTt7JrZHftgeHHBmjB0wgfaUpdxol1DPWclwMcCrsO9yoM0FuCOiCcCgXc//9Q==",
"requires": {
- "@types/geojson": "7946.0.7",
- "@types/node": "12.12.32",
- "denque": "1.4.1",
- "iconv-lite": "0.5.1",
- "long": "4.0.0",
- "moment-timezone": "0.5.28"
+ "@types/geojson": "^7946.0.7",
+ "@types/node": "^14.14.28",
+ "denque": "^1.5.0",
+ "iconv-lite": "^0.6.3",
+ "long": "^4.0.0",
+ "moment-timezone": "^0.5.33",
+ "please-upgrade-node": "^3.2.0"
},
"dependencies": {
+ "@types/node": {
+ "version": "14.18.29",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.29.tgz",
+ "integrity": "sha512-LhF+9fbIX4iPzhsRLpK5H7iPdvW8L4IwGciXQIOEcuF62+9nw/VQVsOViAOOGxY3OlOKGLFv0sWwJXdwQeTn6A=="
+ },
"iconv-lite": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.1.tgz",
- "integrity": "sha512-ONHr16SQvKZNSqjQT9gy5z24Jw+uqfO02/ngBSBoqChZ+W8qXX7GPRa1RoUnzGADw8K63R1BXUMzarCVQBpY8Q==",
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"requires": {
- "safer-buffer": "2.1.2"
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
}
}
}
},
- "markdown-escapes": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
- "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
- "dev": true
- },
"markdown-table": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz",
- "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.2.tgz",
+ "integrity": "sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==",
"dev": true
},
"matchit": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/matchit/-/matchit-1.0.8.tgz",
- "integrity": "sha512-CwPPICzozd/ezCzpVwGYG5bMVieaapnA0vvHDQnmQ2u2vZtVLynoPmvFsZjL67hFOvTBhhpqSR0bq3uloDP/Rw==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/matchit/-/matchit-1.1.0.tgz",
+ "integrity": "sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==",
"dev": true,
"requires": {
- "@arr/every": "1.0.1"
+ "@arr/every": "^1.0.0"
}
},
- "math-interval-parser": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/math-interval-parser/-/math-interval-parser-2.0.1.tgz",
- "integrity": "sha512-VmlAmb0UJwlvMyx8iPhXUDnVW1F9IrGEd9CIOmv+XL8AErCUUuozoDMrgImvnYt2A+53qVX/tPW6YJurMKYsvA=="
- },
"mdast-builder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/mdast-builder/-/mdast-builder-1.1.1.tgz",
"integrity": "sha512-a3KBk/LmYD6wKsWi8WJrGU/rXR4yuF4Men0JO0z6dSZCm5FrXXWTRDjqK0vGSqa+1M6p9edeuypZAZAzSehTUw==",
"dev": true,
"requires": {
- "@types/unist": "2.0.3"
+ "@types/unist": "^2.0.3"
}
},
- "mdast-util-compact": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz",
- "integrity": "sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg==",
+ "mdast-util-find-and-replace": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.1.0.tgz",
+ "integrity": "sha512-1w1jbqAd13oU78QPBf5223+xB+37ecNtQ1JElq2feWols5oEYAl+SgNDnOZipe7NfLemoEt362yUS15/wip4mw==",
"dev": true,
"requires": {
- "unist-util-visit": "1.4.1"
+ "escape-string-regexp": "^5.0.0",
+ "unist-util-is": "^5.0.0",
+ "unist-util-visit-parents": "^4.0.0"
+ },
+ "dependencies": {
+ "escape-string-regexp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+ "dev": true
+ }
+ }
+ },
+ "mdast-util-from-markdown": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz",
+ "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==",
+ "dev": true,
+ "requires": {
+ "@types/mdast": "^3.0.0",
+ "@types/unist": "^2.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "mdast-util-to-string": "^3.1.0",
+ "micromark": "^3.0.0",
+ "micromark-util-decode-numeric-character-reference": "^1.0.0",
+ "micromark-util-decode-string": "^1.0.0",
+ "micromark-util-normalize-identifier": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "unist-util-stringify-position": "^3.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "mdast-util-gfm": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.1.tgz",
+ "integrity": "sha512-42yHBbfWIFisaAfV1eixlabbsa6q7vHeSPY+cg+BBjX51M8xhgMacqH9g6TftB/9+YkcI0ooV4ncfrJslzm/RQ==",
+ "dev": true,
+ "requires": {
+ "mdast-util-from-markdown": "^1.0.0",
+ "mdast-util-gfm-autolink-literal": "^1.0.0",
+ "mdast-util-gfm-footnote": "^1.0.0",
+ "mdast-util-gfm-strikethrough": "^1.0.0",
+ "mdast-util-gfm-table": "^1.0.0",
+ "mdast-util-gfm-task-list-item": "^1.0.0",
+ "mdast-util-to-markdown": "^1.0.0"
+ }
+ },
+ "mdast-util-gfm-autolink-literal": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.2.tgz",
+ "integrity": "sha512-FzopkOd4xTTBeGXhXSBU0OCDDh5lUj2rd+HQqG92Ld+jL4lpUfgX2AT2OHAVP9aEeDKp7G92fuooSZcYJA3cRg==",
+ "dev": true,
+ "requires": {
+ "@types/mdast": "^3.0.0",
+ "ccount": "^2.0.0",
+ "mdast-util-find-and-replace": "^2.0.0",
+ "micromark-util-character": "^1.0.0"
+ }
+ },
+ "mdast-util-gfm-footnote": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.1.tgz",
+ "integrity": "sha512-p+PrYlkw9DeCRkTVw1duWqPRHX6Ywh2BNKJQcZbCwAuP/59B0Lk9kakuAd7KbQprVO4GzdW8eS5++A9PUSqIyw==",
+ "dev": true,
+ "requires": {
+ "@types/mdast": "^3.0.0",
+ "mdast-util-to-markdown": "^1.3.0",
+ "micromark-util-normalize-identifier": "^1.0.0"
+ }
+ },
+ "mdast-util-gfm-strikethrough": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.1.tgz",
+ "integrity": "sha512-zKJbEPe+JP6EUv0mZ0tQUyLQOC+FADt0bARldONot/nefuISkaZFlmVK4tU6JgfyZGrky02m/I6PmehgAgZgqg==",
+ "dev": true,
+ "requires": {
+ "@types/mdast": "^3.0.0",
+ "mdast-util-to-markdown": "^1.3.0"
+ }
+ },
+ "mdast-util-gfm-table": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.4.tgz",
+ "integrity": "sha512-aEuoPwZyP4iIMkf2cLWXxx3EQ6Bmh2yKy9MVCg4i6Sd3cX80dcLEfXO/V4ul3pGH9czBK4kp+FAl+ZHmSUt9/w==",
+ "dev": true,
+ "requires": {
+ "markdown-table": "^3.0.0",
+ "mdast-util-from-markdown": "^1.0.0",
+ "mdast-util-to-markdown": "^1.3.0"
+ }
+ },
+ "mdast-util-gfm-task-list-item": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.1.tgz",
+ "integrity": "sha512-KZ4KLmPdABXOsfnM6JHUIjxEvcx2ulk656Z/4Balw071/5qgnhz+H1uGtf2zIGnrnvDC8xR4Fj9uKbjAFGNIeA==",
+ "dev": true,
+ "requires": {
+ "@types/mdast": "^3.0.0",
+ "mdast-util-to-markdown": "^1.3.0"
+ }
+ },
+ "mdast-util-to-markdown": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.3.0.tgz",
+ "integrity": "sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA==",
+ "dev": true,
+ "requires": {
+ "@types/mdast": "^3.0.0",
+ "@types/unist": "^2.0.0",
+ "longest-streak": "^3.0.0",
+ "mdast-util-to-string": "^3.0.0",
+ "micromark-util-decode-string": "^1.0.0",
+ "unist-util-visit": "^4.0.0",
+ "zwitch": "^2.0.0"
}
},
"mdast-util-to-string": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz",
- "integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz",
+ "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==",
"dev": true
},
"media-typer": {
@@ -2618,297 +8564,628 @@
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
- "mensch": {
- "version": "0.3.4",
- "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz",
- "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g=="
- },
"merge-descriptors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="
},
- "messageformat": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/messageformat/-/messageformat-2.3.0.tgz",
- "integrity": "sha512-uTzvsv0lTeQxYI2y1NPa1lItL5VRI8Gb93Y2K2ue5gBPyrbJxfDi/EYWxh2PKv5yO42AJeeqblS9MJSh/IEk4w==",
- "requires": {
- "make-plural": "4.3.0",
- "messageformat-formatters": "2.0.1",
- "messageformat-parser": "4.1.2"
- },
- "dependencies": {
- "make-plural": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-4.3.0.tgz",
- "integrity": "sha512-xTYd4JVHpSCW+aqDof6w/MebaMVNTVYBZhbB/vi513xXdiPT92JMVCo0Jq8W2UZnzYRFeVbQiQ+I25l13JuKvA==",
- "requires": {
- "minimist": "1.2.5"
- }
- },
- "minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
- "optional": true
- }
- }
- },
- "messageformat-formatters": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/messageformat-formatters/-/messageformat-formatters-2.0.1.tgz",
- "integrity": "sha512-E/lQRXhtHwGuiQjI7qxkLp8AHbMD5r2217XNe/SREbBlSawe0lOqsFb7rflZJmlQFSULNLIqlcjjsCPlB3m3Mg=="
- },
- "messageformat-parser": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-4.1.2.tgz",
- "integrity": "sha512-7dWuifeyldz7vhEuL96Kwq1fhZXBW+TUfbnHN4UCrCxoXQTYjHnR78eI66Gk9LaLLsAvzPNVJBaa66DRfFNaiA=="
+ "merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
+ "micromark": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz",
+ "integrity": "sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg==",
+ "dev": true,
+ "requires": {
+ "@types/debug": "^4.0.0",
+ "debug": "^4.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "micromark-core-commonmark": "^1.0.1",
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-combine-extensions": "^1.0.0",
+ "micromark-util-decode-numeric-character-reference": "^1.0.0",
+ "micromark-util-encode": "^1.0.0",
+ "micromark-util-normalize-identifier": "^1.0.0",
+ "micromark-util-resolve-all": "^1.0.0",
+ "micromark-util-sanitize-uri": "^1.0.0",
+ "micromark-util-subtokenize": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.1",
+ "uvu": "^0.5.0"
+ }
+ },
+ "micromark-core-commonmark": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz",
+ "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==",
+ "dev": true,
+ "requires": {
+ "decode-named-character-reference": "^1.0.0",
+ "micromark-factory-destination": "^1.0.0",
+ "micromark-factory-label": "^1.0.0",
+ "micromark-factory-space": "^1.0.0",
+ "micromark-factory-title": "^1.0.0",
+ "micromark-factory-whitespace": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-classify-character": "^1.0.0",
+ "micromark-util-html-tag-name": "^1.0.0",
+ "micromark-util-normalize-identifier": "^1.0.0",
+ "micromark-util-resolve-all": "^1.0.0",
+ "micromark-util-subtokenize": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.1",
+ "uvu": "^0.5.0"
+ }
+ },
+ "micromark-extension-gfm": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.1.tgz",
+ "integrity": "sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA==",
+ "dev": true,
+ "requires": {
+ "micromark-extension-gfm-autolink-literal": "^1.0.0",
+ "micromark-extension-gfm-footnote": "^1.0.0",
+ "micromark-extension-gfm-strikethrough": "^1.0.0",
+ "micromark-extension-gfm-table": "^1.0.0",
+ "micromark-extension-gfm-tagfilter": "^1.0.0",
+ "micromark-extension-gfm-task-list-item": "^1.0.0",
+ "micromark-util-combine-extensions": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "micromark-extension-gfm-autolink-literal": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.3.tgz",
+ "integrity": "sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg==",
+ "dev": true,
+ "requires": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-sanitize-uri": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "micromark-extension-gfm-footnote": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.4.tgz",
+ "integrity": "sha512-E/fmPmDqLiMUP8mLJ8NbJWJ4bTw6tS+FEQS8CcuDtZpILuOb2kjLqPEeAePF1djXROHXChM/wPJw0iS4kHCcIg==",
+ "dev": true,
+ "requires": {
+ "micromark-core-commonmark": "^1.0.0",
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-normalize-identifier": "^1.0.0",
+ "micromark-util-sanitize-uri": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "micromark-extension-gfm-strikethrough": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.4.tgz",
+ "integrity": "sha512-/vjHU/lalmjZCT5xt7CcHVJGq8sYRm80z24qAKXzaHzem/xsDYb2yLL+NNVbYvmpLx3O7SYPuGL5pzusL9CLIQ==",
+ "dev": true,
+ "requires": {
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-classify-character": "^1.0.0",
+ "micromark-util-resolve-all": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "micromark-extension-gfm-table": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz",
+ "integrity": "sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg==",
+ "dev": true,
+ "requires": {
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "micromark-extension-gfm-tagfilter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.1.tgz",
+ "integrity": "sha512-Ty6psLAcAjboRa/UKUbbUcwjVAv5plxmpUTy2XC/3nJFL37eHej8jrHrRzkqcpipJliuBH30DTs7+3wqNcQUVA==",
+ "dev": true,
+ "requires": {
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "micromark-extension-gfm-task-list-item": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.3.tgz",
+ "integrity": "sha512-PpysK2S1Q/5VXi72IIapbi/jliaiOFzv7THH4amwXeYXLq3l1uo8/2Be0Ac1rEwK20MQEsGH2ltAZLNY2KI/0Q==",
+ "dev": true,
+ "requires": {
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "micromark-factory-destination": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz",
+ "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==",
+ "dev": true,
+ "requires": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "micromark-factory-label": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz",
+ "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==",
+ "dev": true,
+ "requires": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "micromark-factory-space": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz",
+ "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==",
+ "dev": true,
+ "requires": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "micromark-factory-title": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz",
+ "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==",
+ "dev": true,
+ "requires": {
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "micromark-factory-whitespace": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz",
+ "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==",
+ "dev": true,
+ "requires": {
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "micromark-util-character": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz",
+ "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==",
+ "dev": true,
+ "requires": {
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "micromark-util-chunked": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz",
+ "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==",
+ "dev": true,
+ "requires": {
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "micromark-util-classify-character": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz",
+ "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==",
+ "dev": true,
+ "requires": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "micromark-util-combine-extensions": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz",
+ "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==",
+ "dev": true,
+ "requires": {
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "micromark-util-decode-numeric-character-reference": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz",
+ "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==",
+ "dev": true,
+ "requires": {
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "micromark-util-decode-string": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz",
+ "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==",
+ "dev": true,
+ "requires": {
+ "decode-named-character-reference": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-decode-numeric-character-reference": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "micromark-util-encode": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz",
+ "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==",
+ "dev": true
+ },
+ "micromark-util-html-tag-name": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.0.0.tgz",
+ "integrity": "sha512-NenEKIshW2ZI/ERv9HtFNsrn3llSPZtY337LID/24WeLqMzeZhBEE6BQ0vS2ZBjshm5n40chKtJ3qjAbVV8S0g==",
+ "dev": true
+ },
+ "micromark-util-normalize-identifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz",
+ "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==",
+ "dev": true,
+ "requires": {
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "micromark-util-resolve-all": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz",
+ "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==",
+ "dev": true,
+ "requires": {
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "micromark-util-sanitize-uri": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz",
+ "integrity": "sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg==",
+ "dev": true,
+ "requires": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-encode": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "micromark-util-subtokenize": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz",
+ "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==",
+ "dev": true,
+ "requires": {
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "micromark-util-symbol": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz",
+ "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==",
+ "dev": true
+ },
+ "micromark-util-types": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz",
+ "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "requires": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ }
+ },
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
},
"mime-db": {
- "version": "1.35.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
- "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg=="
+ "version": "1.51.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
+ "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="
},
"mime-types": {
- "version": "2.1.19",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
- "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
+ "version": "2.1.34",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
+ "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
"requires": {
- "mime-db": "1.35.0"
+ "mime-db": "1.51.0"
}
},
- "mimer": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/mimer/-/mimer-1.0.0.tgz",
- "integrity": "sha512-4ZJvCzfcwsBgPbkKXUzGoVZMWjv8IDIygkGzVc7uUYhgnK0t2LmGxxjdgH1i+pn0/KQfB5F/VKUJlfyTSOFQjg=="
- },
"minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"requires": {
- "brace-expansion": "1.1.11"
+ "brace-expansion": "^1.1.7"
}
},
- "minimist": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
- },
"minipass": {
- "version": "2.3.5",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
- "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "optional": true,
"requires": {
- "safe-buffer": "5.1.2",
- "yallist": "3.0.3"
+ "yallist": "^4.0.0"
+ }
+ },
+ "minipass-collect": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz",
+ "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==",
+ "optional": true,
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
+ "minipass-fetch": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz",
+ "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==",
+ "optional": true,
+ "requires": {
+ "encoding": "^0.1.12",
+ "minipass": "^3.1.0",
+ "minipass-sized": "^1.0.3",
+ "minizlib": "^2.0.0"
+ }
+ },
+ "minipass-flush": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
+ "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
+ "optional": true,
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
+ "minipass-pipeline": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
+ "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
+ "optional": true,
+ "requires": {
+ "minipass": "^3.0.0"
+ }
+ },
+ "minipass-sized": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz",
+ "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==",
+ "optional": true,
+ "requires": {
+ "minipass": "^3.0.0"
}
},
"minizlib": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
- "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
"optional": true,
"requires": {
- "minipass": "2.3.5"
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
}
},
"mkdirp": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
- "requires": {
- "minimist": "0.0.8"
- }
- },
- "moment": {
- "version": "2.24.0",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
- "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
- },
- "moment-timezone": {
- "version": "0.5.28",
- "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.28.tgz",
- "integrity": "sha512-TDJkZvAyKIVWg5EtVqRzU97w0Rb0YVbfpqyjgu6GwXCAohVRqwZjf4fOzDE6p1Ch98Sro/8hQQi65WDXW5STPw==",
- "requires": {
- "moment": "2.24.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "multimatch": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz",
- "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==",
- "requires": {
- "@types/minimatch": "3.0.3",
- "array-differ": "3.0.0",
- "array-union": "2.1.0",
- "arrify": "2.0.1",
- "minimatch": "3.0.4"
- }
- },
- "mustache": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.0.1.tgz",
- "integrity": "sha512-yL5VE97+OXn4+Er3THSmTdCFCtx5hHWzrolvH+JObZnUYwuaG7XV+Ch4fR2cIrcYI0tFHxS7iyFYl14bW8y2sA=="
- },
- "nan": {
- "version": "2.10.0",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
- "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"optional": true
},
- "needle": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz",
- "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==",
+ "moment": {
+ "version": "2.29.4",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
+ },
+ "moment-timezone": {
+ "version": "0.5.37",
+ "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.37.tgz",
+ "integrity": "sha512-uEDzDNFhfaywRl+vwXxffjjq1q0Vzr+fcQpQ1bU0kbzorfS7zVtZnCnGc8mhWmF39d4g4YriF6kwA75mJKE/Zg==",
+ "requires": {
+ "moment": ">= 2.9.0"
+ }
+ },
+ "mri": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+ "dev": true
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
+ "negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
+ },
+ "node-addon-api": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+ "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
+ "optional": true
+ },
+ "node-fetch": {
+ "version": "2.6.11",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
+ "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
"optional": true,
"requires": {
- "debug": "2.6.9",
- "iconv-lite": "0.4.23",
- "sax": "1.2.4"
+ "whatwg-url": "^5.0.0"
},
"dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "optional": true
+ },
+ "webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "optional": true
+ },
+ "whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"optional": true,
"requires": {
- "ms": "2.0.0"
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
}
}
}
},
- "negotiator": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
- "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
- },
- "nice-try": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
- "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
- },
- "node-pre-gyp": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz",
- "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==",
+ "node-gyp": {
+ "version": "8.4.1",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz",
+ "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==",
"optional": true,
"requires": {
- "detect-libc": "1.0.3",
- "mkdirp": "0.5.1",
- "needle": "2.2.4",
- "nopt": "4.0.1",
- "npm-packlist": "1.4.1",
- "npmlog": "4.1.2",
- "rc": "1.2.8",
- "rimraf": "2.7.1",
- "semver": "5.5.0",
- "tar": "4.4.8"
+ "env-paths": "^2.2.0",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.6",
+ "make-fetch-happen": "^9.1.0",
+ "nopt": "^5.0.0",
+ "npmlog": "^6.0.0",
+ "rimraf": "^3.0.2",
+ "semver": "^7.3.5",
+ "tar": "^6.1.2",
+ "which": "^2.0.2"
},
"dependencies": {
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "are-we-there-yet": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz",
+ "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==",
"optional": true,
"requires": {
- "glob": "7.1.6"
+ "delegates": "^1.0.0",
+ "readable-stream": "^3.6.0"
+ }
+ },
+ "gauge": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz",
+ "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==",
+ "optional": true,
+ "requires": {
+ "aproba": "^1.0.3 || ^2.0.0",
+ "color-support": "^1.1.3",
+ "console-control-strings": "^1.1.0",
+ "has-unicode": "^2.0.1",
+ "signal-exit": "^3.0.7",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1",
+ "wide-align": "^1.1.5"
+ }
+ },
+ "npmlog": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz",
+ "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==",
+ "optional": true,
+ "requires": {
+ "are-we-there-yet": "^3.0.0",
+ "console-control-strings": "^1.1.0",
+ "gauge": "^4.0.3",
+ "set-blocking": "^2.0.0"
}
}
}
},
"nodemailer": {
- "version": "6.4.6",
- "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.6.tgz",
- "integrity": "sha512-/kJ+FYVEm2HuUlw87hjSqTss+GU35D4giOpdSfGp7DO+5h6RlJj7R94YaYHOkoxu1CSaM0d3WRBtCzwXrY6MKA=="
+ "version": "6.9.9",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.9.tgz",
+ "integrity": "sha512-dexTll8zqQoVJEZPwQAKzxxtFn0qTnjdQTchoU6Re9BUUGBJiOy3YMn/0ShTW6J5M0dfQ1NeDeRTTl4oIWgQMA=="
},
"nopt": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
- "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+ "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
"optional": true,
"requires": {
- "abbrev": "1.1.1",
- "osenv": "0.1.5"
- }
- },
- "npm-bundled": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
- "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
- "optional": true
- },
- "npm-packlist": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz",
- "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
- "optional": true,
- "requires": {
- "ignore-walk": "3.0.1",
- "npm-bundled": "1.0.6"
+ "abbrev": "1"
}
},
"npmlog": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
- "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
+ "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
"optional": true,
"requires": {
- "are-we-there-yet": "1.1.5",
- "console-control-strings": "1.1.0",
- "gauge": "2.7.4",
- "set-blocking": "2.0.0"
+ "are-we-there-yet": "^2.0.0",
+ "console-control-strings": "^1.1.0",
+ "gauge": "^3.0.0",
+ "set-blocking": "^2.0.0"
}
},
- "nth-check": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
- "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
- "requires": {
- "boolbase": "1.0.0"
- }
- },
- "number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
- },
- "oauth-sign": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
- "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
- "optional": true
- },
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
- "object-component": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
- "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="
+ "object-inspect": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
+ "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g=="
},
"on-finished": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
- "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"requires": {
"ee-first": "1.1.1"
}
@@ -2917,97 +9194,64 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "devOptional": true,
"requires": {
- "wrappy": "1.0.2"
+ "wrappy": "1"
}
},
- "open": {
- "version": "6.4.0",
- "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz",
- "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==",
+ "optionator": {
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
+ "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
+ "dev": true,
"requires": {
- "is-wsl": "1.1.0"
- }
- },
- "os-homedir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
- "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
- "optional": true
- },
- "os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
- "optional": true
- },
- "osenv": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
- "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
- "optional": true,
- "requires": {
- "os-homedir": "1.0.2",
- "os-tmpdir": "1.0.2"
+ "@aashutoshrathi/word-wrap": "^1.2.3",
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0"
}
},
"p-limit": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
- "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"requires": {
- "p-try": "2.2.0"
+ "yocto-queue": "^0.1.0"
}
},
"p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"requires": {
- "p-limit": "2.2.2"
+ "p-limit": "^3.0.2"
}
},
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
+ "p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "optional": true,
+ "requires": {
+ "aggregate-error": "^3.0.0"
+ }
},
"packet-reader": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
"integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ=="
},
- "parse-entities": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz",
- "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==",
+ "parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
"requires": {
- "character-entities": "1.2.4",
- "character-entities-legacy": "1.1.4",
- "character-reference-invalid": "1.1.4",
- "is-alphanumerical": "1.0.4",
- "is-decimal": "1.0.4",
- "is-hexadecimal": "1.0.4"
- }
- },
- "parseqs": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
- "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
- "requires": {
- "better-assert": "1.0.2"
- }
- },
- "parseuri": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
- "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
- "requires": {
- "better-assert": "1.0.2"
+ "callsites": "^3.0.0"
}
},
"parseurl": {
@@ -3016,69 +9260,64 @@
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
},
"path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "devOptional": true
},
"path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true
},
"path-parse": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
- "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"path-to-regexp": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
},
- "performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
},
"pg": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/pg/-/pg-7.18.2.tgz",
- "integrity": "sha512-Mvt0dGYMwvEADNKy5PMQGlzPudKcKKzJds/VbOeZJpb6f/pI3mmoXX0JksPgI3l3JPP/2Apq7F36O63J7mgveA==",
+ "version": "8.7.1",
+ "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz",
+ "integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==",
"requires": {
"buffer-writer": "2.0.0",
"packet-reader": "1.0.0",
- "pg-connection-string": "0.1.3",
- "pg-packet-stream": "1.1.0",
- "pg-pool": "2.0.10",
- "pg-types": "2.2.0",
- "pgpass": "1.0.2",
- "semver": "4.3.2"
- },
- "dependencies": {
- "semver": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz",
- "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c="
- }
+ "pg-connection-string": "^2.5.0",
+ "pg-pool": "^3.4.1",
+ "pg-protocol": "^1.5.0",
+ "pg-types": "^2.1.0",
+ "pgpass": "1.x"
}
},
"pg-connection-string": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz",
- "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc="
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
+ "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
},
"pg-hstore": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.3.tgz",
- "integrity": "sha512-qpeTpdkguFgfdoidtfeTho1Q1zPVPbtMHgs8eQ+Aan05iLmIs3Z3oo5DOZRclPGoQ4i68I1kCtQSJSa7i0ZVYg==",
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.4.tgz",
+ "integrity": "sha512-N3SGs/Rf+xA1M2/n0JBiXFDVMzdekwLZLAO0g7mpDY9ouX+fDI7jS6kTq3JujmYbtNSJ53TJ0q4G98KVZSM4EA==",
"requires": {
- "underscore": "1.7.0"
+ "underscore": "^1.13.1"
}
},
"pg-int8": {
@@ -3086,15 +9325,16 @@
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="
},
- "pg-packet-stream": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/pg-packet-stream/-/pg-packet-stream-1.1.0.tgz",
- "integrity": "sha512-kRBH0tDIW/8lfnnOyTwKD23ygJ/kexQVXZs7gEyBljw4FYqimZFxnMMx50ndZ8In77QgfGuItS5LLclC2TtjYg=="
- },
"pg-pool": {
- "version": "2.0.10",
- "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.10.tgz",
- "integrity": "sha512-qdwzY92bHf3nwzIUcj+zJ0Qo5lpG/YxchahxIN8+ZVmXqkahKXsnl2aiJPHLYN9o5mB/leG+Xh6XKxtP7e0sjg=="
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz",
+ "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==",
+ "requires": {}
+ },
+ "pg-protocol": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
+ "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ=="
},
"pg-types": {
"version": "2.2.0",
@@ -3102,34 +9342,41 @@
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
"requires": {
"pg-int8": "1.0.1",
- "postgres-array": "2.0.0",
- "postgres-bytea": "1.0.0",
- "postgres-date": "1.0.4",
- "postgres-interval": "1.2.0"
+ "postgres-array": "~2.0.0",
+ "postgres-bytea": "~1.0.0",
+ "postgres-date": "~1.0.4",
+ "postgres-interval": "^1.1.0"
}
},
"pgpass": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz",
- "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=",
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
+ "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
"requires": {
- "split": "1.0.1"
+ "split2": "^4.1.0"
}
},
"phin": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/phin/-/phin-3.4.1.tgz",
- "integrity": "sha512-NkBCNRPxeyrgaPlWx4DHTAdca3s2LkvIBiiG6RoSbykcOtW/pA/7rUP/67FPIinvbo7h+HENST/vJ17LdRNUdw==",
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz",
+ "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==",
"dev": true,
"requires": {
- "centra": "2.4.0"
+ "centra": "^2.7.0"
}
},
"picomatch": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
- "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
- "dev": true
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
+ },
+ "please-upgrade-node": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+ "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+ "requires": {
+ "semver-compare": "^1.0.0"
+ }
},
"polka": {
"version": "0.5.2",
@@ -3137,10 +9384,15 @@
"integrity": "sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==",
"dev": true,
"requires": {
- "@polka/url": "0.5.0",
- "trouter": "2.0.1"
+ "@polka/url": "^0.5.0",
+ "trouter": "^2.0.1"
}
},
+ "pony-cause": {
+ "version": "2.1.11",
+ "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz",
+ "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg=="
+ },
"postgres-array": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
@@ -3152,210 +9404,66 @@
"integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU="
},
"postgres-date": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.4.tgz",
- "integrity": "sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA=="
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
+ "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="
},
"postgres-interval": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
"requires": {
- "xtend": "4.0.2"
+ "xtend": "^4.0.0"
}
},
- "preview-email": {
+ "prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true
+ },
+ "promise-inflight": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+ "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==",
+ "optional": true
+ },
+ "promise-retry": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/preview-email/-/preview-email-2.0.1.tgz",
- "integrity": "sha512-KXmv0oKonf9slHXjZ1O+QvGsq7IKJs3IINB4b8XWZ3IwONyGiGqpXthCrTZuDzhLG1kPn6FKOOikdm21bturcQ==",
+ "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
+ "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+ "optional": true,
"requires": {
- "@babel/runtime": "7.9.2",
- "dayjs": "1.8.23",
- "debug": "4.1.1",
- "mailparser": "2.7.7",
- "nodemailer": "6.4.6",
- "open": "6.4.0",
- "pify": "4.0.1",
- "pug": "2.0.4",
- "uuid": "3.4.0"
- },
- "dependencies": {
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
- },
- "uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
- }
- }
- },
- "process-nextick-args": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
- "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
- },
- "promise": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
- "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
- "requires": {
- "asap": "2.0.6"
+ "err-code": "^2.0.2",
+ "retry": "^0.12.0"
}
},
"proxy-addr": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
- "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
"requires": {
- "forwarded": "0.1.2",
- "ipaddr.js": "1.9.0"
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
}
},
- "psl": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
- "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
- },
- "pug": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/pug/-/pug-2.0.4.tgz",
- "integrity": "sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw==",
- "requires": {
- "pug-code-gen": "2.0.2",
- "pug-filters": "3.1.1",
- "pug-lexer": "4.1.0",
- "pug-linker": "3.0.6",
- "pug-load": "2.0.12",
- "pug-parser": "5.0.1",
- "pug-runtime": "2.0.5",
- "pug-strip-comments": "1.0.4"
- }
- },
- "pug-attrs": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-2.0.4.tgz",
- "integrity": "sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ==",
- "requires": {
- "constantinople": "3.1.2",
- "js-stringify": "1.0.2",
- "pug-runtime": "2.0.5"
- }
- },
- "pug-code-gen": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-2.0.2.tgz",
- "integrity": "sha512-kROFWv/AHx/9CRgoGJeRSm+4mLWchbgpRzTEn8XCiwwOy6Vh0gAClS8Vh5TEJ9DBjaP8wCjS3J6HKsEsYdvaCw==",
- "requires": {
- "constantinople": "3.1.2",
- "doctypes": "1.1.0",
- "js-stringify": "1.0.2",
- "pug-attrs": "2.0.4",
- "pug-error": "1.3.3",
- "pug-runtime": "2.0.5",
- "void-elements": "2.0.1",
- "with": "5.1.1"
- }
- },
- "pug-error": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-1.3.3.tgz",
- "integrity": "sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ=="
- },
- "pug-filters": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-3.1.1.tgz",
- "integrity": "sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg==",
- "requires": {
- "clean-css": "4.2.3",
- "constantinople": "3.1.2",
- "jstransformer": "1.0.0",
- "pug-error": "1.3.3",
- "pug-walk": "1.1.8",
- "resolve": "1.12.0",
- "uglify-js": "2.8.29"
- }
- },
- "pug-lexer": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-4.1.0.tgz",
- "integrity": "sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA==",
- "requires": {
- "character-parser": "2.2.0",
- "is-expression": "3.0.0",
- "pug-error": "1.3.3"
- }
- },
- "pug-linker": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-3.0.6.tgz",
- "integrity": "sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg==",
- "requires": {
- "pug-error": "1.3.3",
- "pug-walk": "1.1.8"
- }
- },
- "pug-load": {
- "version": "2.0.12",
- "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-2.0.12.tgz",
- "integrity": "sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg==",
- "requires": {
- "object-assign": "4.1.1",
- "pug-walk": "1.1.8"
- }
- },
- "pug-parser": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-5.0.1.tgz",
- "integrity": "sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA==",
- "requires": {
- "pug-error": "1.3.3",
- "token-stream": "0.0.1"
- }
- },
- "pug-runtime": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-2.0.5.tgz",
- "integrity": "sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw=="
- },
- "pug-strip-comments": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz",
- "integrity": "sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw==",
- "requires": {
- "pug-error": "1.3.3"
- }
- },
- "pug-walk": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.8.tgz",
- "integrity": "sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA=="
- },
"punycode": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
- "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
- "optional": true
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"qs": {
- "version": "6.5.2",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
- "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
+ "requires": {
+ "side-channel": "^1.0.6"
+ }
+ },
+ "queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
},
"range-parser": {
"version": "1.2.1",
@@ -3363,173 +9471,97 @@
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
"rate-limiter-flexible": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.1.3.tgz",
- "integrity": "sha512-xpUP6qDd4QTgg61D/OBekrpQralUJnfSfYweS/Msmz1d3qpg+XThOvLjgpY+7NgoakMk9mBlNdJlSmP/sXBS5Q=="
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.3.6.tgz",
+ "integrity": "sha512-8DVFOe89rreyut/vzwBI7vgXJynyYoYnH5XogtAKs0F/neAbCTTglXxSJ7fZeZamcFXZDvMidCBvps4KM+1srw=="
},
"raw-body": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
- "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
"requires": {
- "bytes": "3.1.0",
- "http-errors": "1.7.2",
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
"dependencies": {
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
"http-errors": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
- "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"requires": {
- "depd": "1.1.2",
- "inherits": "2.0.3",
- "setprototypeof": "1.1.1",
- "statuses": "1.5.0",
- "toidentifier": "1.0.0"
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
}
},
- "iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "requires": {
- "safer-buffer": "2.1.2"
- }
- }
- }
- },
- "rc": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
- "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
- "optional": true,
- "requires": {
- "deep-extend": "0.6.0",
- "ini": "1.3.5",
- "minimist": "1.2.0",
- "strip-json-comments": "2.0.1"
- },
- "dependencies": {
- "minimist": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
- "optional": true
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
}
}
},
"readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "optional": true,
"requires": {
- "core-util-is": "1.0.2",
- "inherits": "2.0.3",
- "isarray": "1.0.0",
- "process-nextick-args": "2.0.0",
- "safe-buffer": "5.1.2",
- "string_decoder": "1.1.1",
- "util-deprecate": "1.0.2"
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
}
},
"readdirp": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
- "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==",
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"requires": {
- "picomatch": "2.2.2"
+ "picomatch": "^2.2.1"
}
},
- "regenerator-runtime": {
- "version": "0.13.5",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
- "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA=="
- },
- "remark-parse": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-7.0.2.tgz",
- "integrity": "sha512-9+my0lQS80IQkYXsMA8Sg6m9QfXYJBnXjWYN5U+kFc5/n69t+XZVXU/ZBYr3cYH8FheEGf1v87rkFDhJ8bVgMA==",
+ "remark-gfm": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz",
+ "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==",
"dev": true,
"requires": {
- "collapse-white-space": "1.0.6",
- "is-alphabetical": "1.0.4",
- "is-decimal": "1.0.4",
- "is-whitespace-character": "1.0.4",
- "is-word-character": "1.0.4",
- "markdown-escapes": "1.0.4",
- "parse-entities": "1.2.2",
- "repeat-string": "1.6.1",
- "state-toggle": "1.0.3",
- "trim": "0.0.1",
- "trim-trailing-lines": "1.1.3",
- "unherit": "1.1.3",
- "unist-util-remove-position": "1.1.4",
- "vfile-location": "2.0.6",
- "xtend": "4.0.2"
+ "@types/mdast": "^3.0.0",
+ "mdast-util-gfm": "^2.0.0",
+ "micromark-extension-gfm": "^2.0.0",
+ "unified": "^10.0.0"
+ }
+ },
+ "remark-parse": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz",
+ "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==",
+ "dev": true,
+ "requires": {
+ "@types/mdast": "^3.0.0",
+ "mdast-util-from-markdown": "^1.0.0",
+ "unified": "^10.0.0"
}
},
"remark-stringify": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-7.0.4.tgz",
- "integrity": "sha512-qck+8NeA1D0utk1ttKcWAoHRrJxERYQzkHDyn+pF5Z4whX1ug98uCNPPSeFgLSaNERRxnD6oxIug6DzZQth6Pg==",
+ "version": "10.0.2",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-10.0.2.tgz",
+ "integrity": "sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw==",
"dev": true,
"requires": {
- "ccount": "1.0.5",
- "is-alphanumeric": "1.0.0",
- "is-decimal": "1.0.4",
- "is-whitespace-character": "1.0.4",
- "longest-streak": "2.0.4",
- "markdown-escapes": "1.0.4",
- "markdown-table": "1.1.3",
- "mdast-util-compact": "1.0.4",
- "parse-entities": "1.2.2",
- "repeat-string": "1.6.1",
- "state-toggle": "1.0.3",
- "stringify-entities": "2.0.0",
- "unherit": "1.1.3",
- "xtend": "4.0.2"
- }
- },
- "repeat-string": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
- "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
- },
- "replace-ext": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
- "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
- "dev": true
- },
- "request": {
- "version": "2.87.0",
- "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz",
- "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==",
- "optional": true,
- "requires": {
- "aws-sign2": "0.7.0",
- "aws4": "1.7.0",
- "caseless": "0.12.0",
- "combined-stream": "1.0.6",
- "extend": "3.0.2",
- "forever-agent": "0.6.1",
- "form-data": "2.3.2",
- "har-validator": "5.0.3",
- "http-signature": "1.2.0",
- "is-typedarray": "1.0.0",
- "isstream": "0.1.2",
- "json-stringify-safe": "5.0.1",
- "mime-types": "2.1.19",
- "oauth-sign": "0.8.2",
- "performance-now": "2.1.0",
- "qs": "6.5.2",
- "safe-buffer": "5.1.2",
- "tough-cookie": "2.3.4",
- "tunnel-agent": "0.6.0",
- "uuid": "3.3.2"
+ "@types/mdast": "^3.0.0",
+ "mdast-util-to-markdown": "^1.0.0",
+ "unified": "^10.0.0"
}
},
"require-directory": {
@@ -3538,43 +9570,67 @@
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
"dev": true
},
- "require-main-filename": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
- "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
- "dev": true
+ "require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
},
"resolve": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
- "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
"requires": {
- "path-parse": "1.0.6"
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
}
},
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ },
+ "retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+ "optional": true
+ },
"retry-as-promised": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz",
- "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==",
- "requires": {
- "any-promise": "1.3.0"
- }
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.0.4.tgz",
+ "integrity": "sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA=="
},
- "right-align": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
- "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
- "requires": {
- "align-text": "0.1.4"
- }
+ "reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
},
"rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "devOptional": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "requires": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "sade": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
+ "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
"dev": true,
"requires": {
- "glob": "7.1.6"
+ "mri": "^1.1.0"
}
},
"safe-buffer": {
@@ -3582,494 +9638,409 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
+ "safe-stable-stringify": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz",
+ "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==",
+ "dev": true
+ },
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
- "sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
- "optional": true
- },
"semver": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
- "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "semver-compare": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+ "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w="
},
"send": {
- "version": "0.17.1",
- "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
- "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+ "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"requires": {
"debug": "2.6.9",
- "depd": "1.1.2",
- "destroy": "1.0.4",
- "encodeurl": "1.0.2",
- "escape-html": "1.0.3",
- "etag": "1.8.1",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
"fresh": "0.5.2",
- "http-errors": "1.7.3",
+ "http-errors": "2.0.0",
"mime": "1.6.0",
- "ms": "2.1.1",
- "on-finished": "2.3.0",
- "range-parser": "1.2.1",
- "statuses": "1.5.0"
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
},
"dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
+ "http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "requires": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ }
+ },
"ms": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
- "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
}
}
},
"sequelize": {
- "version": "5.21.5",
- "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.21.5.tgz",
- "integrity": "sha512-n9hR5K4uQGmBGK/Y/iqewCeSFmKVsd0TRnh0tfoLoAkmXbKC4tpeK96RhKs7d+TTMtrJlgt2TNLVBaAxEwC4iw==",
+ "version": "6.29.0",
+ "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.29.0.tgz",
+ "integrity": "sha512-m8Wi90rs3NZP9coXE52c7PL4Q078nwYZXqt1IxPvgki7nOFn0p/F0eKsYDBXCPw9G8/BCEa6zZNk0DQUAT4ypA==",
"requires": {
- "bluebird": "3.7.2",
- "cls-bluebird": "2.1.0",
- "debug": "4.1.1",
- "dottie": "2.0.2",
- "inflection": "1.12.0",
- "lodash": "4.17.19",
- "moment": "2.24.0",
- "moment-timezone": "0.5.28",
- "retry-as-promised": "3.2.0",
- "semver": "6.3.0",
- "sequelize-pool": "2.3.0",
- "toposort-class": "1.0.1",
- "uuid": "3.4.0",
- "validator": "10.11.0",
- "wkx": "0.4.8"
- },
- "dependencies": {
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- },
- "uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
- }
+ "@types/debug": "^4.1.7",
+ "@types/validator": "^13.7.1",
+ "debug": "^4.3.3",
+ "dottie": "^2.0.2",
+ "inflection": "^1.13.2",
+ "lodash": "^4.17.21",
+ "moment": "^2.29.1",
+ "moment-timezone": "^0.5.35",
+ "pg-connection-string": "^2.5.0",
+ "retry-as-promised": "^7.0.3",
+ "semver": "^7.3.5",
+ "sequelize-pool": "^7.1.0",
+ "toposort-class": "^1.0.1",
+ "uuid": "^8.3.2",
+ "validator": "^13.7.0",
+ "wkx": "^0.5.0"
}
},
"sequelize-pool": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-2.3.0.tgz",
- "integrity": "sha512-Ibz08vnXvkZ8LJTiUOxRcj1Ckdn7qafNZ2t59jYHMX1VIebTAOYefWdRYFt6z6+hy52WGthAHAoLc9hvk3onqA=="
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-7.1.0.tgz",
+ "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg=="
},
"serve-static": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
- "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+ "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"requires": {
- "encodeurl": "1.0.2",
- "escape-html": "1.0.3",
- "parseurl": "1.3.3",
- "send": "0.17.1"
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.19.0"
+ },
+ "dependencies": {
+ "encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="
+ }
}
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+ "optional": true
+ },
+ "set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "requires": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ }
},
"setprototypeof": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
- "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
"requires": {
- "shebang-regex": "1.0.0"
+ "shebang-regex": "^3.0.0"
}
},
"shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true
},
- "shimmer": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz",
- "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="
+ "side-channel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "requires": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ }
},
"signal-exit": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
- "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"optional": true
},
- "slick": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz",
- "integrity": "sha1-vQSN23TefRymkV+qSldXCzVQwtc="
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true
+ },
+ "smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+ "optional": true
},
"socket.io": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz",
- "integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==",
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz",
+ "integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==",
"requires": {
- "debug": "4.1.1",
- "engine.io": "3.4.0",
- "has-binary2": "1.0.3",
- "socket.io-adapter": "1.1.1",
- "socket.io-client": "2.3.0",
- "socket.io-parser": "3.4.0"
- },
- "dependencies": {
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- }
+ "accepts": "~1.3.4",
+ "base64id": "~2.0.0",
+ "cors": "~2.8.5",
+ "debug": "~4.3.2",
+ "engine.io": "~6.6.0",
+ "socket.io-adapter": "~2.5.2",
+ "socket.io-parser": "~4.2.4"
}
},
"socket.io-adapter": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz",
- "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs="
- },
- "socket.io-client": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz",
- "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==",
+ "version": "2.5.5",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
+ "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
"requires": {
- "backo2": "1.0.2",
- "base64-arraybuffer": "0.1.5",
- "component-bind": "1.0.0",
- "component-emitter": "1.2.1",
- "debug": "4.1.1",
- "engine.io-client": "3.4.0",
- "has-binary2": "1.0.3",
- "has-cors": "1.1.0",
- "indexof": "0.0.1",
- "object-component": "0.0.3",
- "parseqs": "0.0.5",
- "parseuri": "0.0.5",
- "socket.io-parser": "3.3.0",
- "to-array": "0.1.4"
- },
- "dependencies": {
- "component-emitter": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
- "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
- },
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "isarray": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
- "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "socket.io-parser": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz",
- "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==",
- "requires": {
- "component-emitter": "1.2.1",
- "debug": "3.1.0",
- "isarray": "2.0.1"
- },
- "dependencies": {
- "debug": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
- "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- }
+ "debug": "~4.3.4",
+ "ws": "~8.17.1"
}
},
"socket.io-parser": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.0.tgz",
- "integrity": "sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==",
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
+ "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"requires": {
- "component-emitter": "1.2.1",
- "debug": "4.1.1",
- "isarray": "2.0.1"
- },
- "dependencies": {
- "component-emitter": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
- "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
- },
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "isarray": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
- "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- }
+ "@socket.io/component-emitter": "~3.1.0",
+ "debug": "~4.3.1"
}
},
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
- },
- "split": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
- "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
- "requires": {
- "through": "2.3.8"
- }
- },
- "sprintf-js": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
- "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
- },
- "sqlite3": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.6.tgz",
- "integrity": "sha512-EqBXxHdKiwvNMRCgml86VTL5TK1i0IKiumnfxykX0gh6H6jaKijAXvE9O1N7+omfNSawR2fOmIyJZcfe8HYWpw==",
+ "socks": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
+ "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
"optional": true,
"requires": {
- "nan": "2.10.0",
- "node-pre-gyp": "0.11.0",
- "request": "2.87.0"
+ "ip-address": "^9.0.5",
+ "smart-buffer": "^4.2.0"
}
},
- "sshpk": {
- "version": "1.14.2",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
- "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
+ "socks-proxy-agent": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz",
+ "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==",
+ "optional": true,
"requires": {
- "asn1": "0.2.3",
- "assert-plus": "1.0.0",
- "bcrypt-pbkdf": "1.0.2",
- "dashdash": "1.14.1",
- "ecc-jsbn": "0.1.2",
- "getpass": "0.1.7",
- "jsbn": "0.1.1",
- "safer-buffer": "2.1.2",
- "tweetnacl": "0.14.5"
+ "agent-base": "^6.0.2",
+ "debug": "^4.3.3",
+ "socks": "^2.6.2"
}
},
- "state-toggle": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
- "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==",
- "dev": true
+ "split2": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz",
+ "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ=="
+ },
+ "sprintf-js": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
+ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
+ "optional": true
+ },
+ "sqlite3": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.6.tgz",
+ "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==",
+ "optional": true,
+ "requires": {
+ "@mapbox/node-pre-gyp": "^1.0.0",
+ "node-addon-api": "^4.2.0",
+ "node-gyp": "8.x",
+ "tar": "^6.1.11"
+ }
+ },
+ "ssri": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
+ "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
+ "optional": true,
+ "requires": {
+ "minipass": "^3.1.1"
+ }
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
- "string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "requires": {
- "code-point-at": "1.1.0",
- "is-fullwidth-code-point": "1.0.0",
- "strip-ansi": "3.0.1"
- }
- },
"string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "optional": true,
"requires": {
- "safe-buffer": "5.1.2"
+ "safe-buffer": "~5.2.0"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "optional": true
+ }
}
},
- "stringify-entities": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-2.0.0.tgz",
- "integrity": "sha512-fqqhZzXyAM6pGD9lky/GOPq6V4X0SeTAFBl0iXb/BzOegl40gpf/bV3QQP7zULNYvjr6+Dx8SCaDULjVoOru0A==",
- "dev": true,
+ "string-argv": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
+ "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="
+ },
+ "string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "devOptional": true,
"requires": {
- "character-entities-html4": "1.1.4",
- "character-entities-legacy": "1.1.4",
- "is-alphanumerical": "1.0.4",
- "is-decimal": "1.0.4",
- "is-hexadecimal": "1.0.4"
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
}
},
"strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "devOptional": true,
"requires": {
- "ansi-regex": "2.1.1"
+ "ansi-regex": "^5.0.1"
}
},
"strip-json-comments": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
- "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
- "optional": true
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true
},
"supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"requires": {
- "has-flag": "3.0.0"
+ "has-flag": "^4.0.0"
}
},
+ "supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
+ },
"tar": {
- "version": "4.4.8",
- "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
- "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+ "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
"optional": true,
"requires": {
- "chownr": "1.1.1",
- "fs-minipass": "1.2.5",
- "minipass": "2.3.5",
- "minizlib": "1.2.1",
- "mkdirp": "0.5.1",
- "safe-buffer": "5.1.2",
- "yallist": "3.0.3"
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^5.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "dependencies": {
+ "minipass": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
+ "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
+ "optional": true
+ }
}
},
- "through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
},
- "titleize": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/titleize/-/titleize-2.1.0.tgz",
- "integrity": "sha512-m+apkYlfiQTKLW+sI4vqUkwMEzfgEUEYSqljx1voUE3Wz/z1ZsxyzSxvH2X8uKVrOp7QkByWt0rA6+gvhCKy6g=="
- },
- "tlds": {
- "version": "1.207.0",
- "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.207.0.tgz",
- "integrity": "sha512-k7d7Q1LqjtAvhtEOs3yN14EabsNO8ZCoY6RESSJDB9lst3bTx3as/m1UuAeCKzYxiyhR1qq72ZPhpSf+qlqiwg=="
- },
- "to-array": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
- "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
- },
- "to-fast-properties": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
- "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc="
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "requires": {
+ "is-number": "^7.0.0"
+ }
},
"toidentifier": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
- "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
- },
- "token-stream": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz",
- "integrity": "sha1-zu78cXp2xDFvEm0LnbqlXX598Bo="
- },
- "tokgen": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/tokgen/-/tokgen-1.0.0.tgz",
- "integrity": "sha1-5wmIWfbnzKXwGSoFW0GN6kJQBOM=",
- "requires": {
- "expand-string": "1.1.1",
- "lodash.defaults": "4.2.0"
- }
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
},
"toposort-class": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz",
"integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg="
},
- "tough-cookie": {
- "version": "2.3.4",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
- "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
- "optional": true,
- "requires": {
- "punycode": "1.4.1"
- }
- },
- "trim": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
- "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=",
- "dev": true
- },
- "trim-trailing-lines": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz",
- "integrity": "sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA==",
- "dev": true
- },
- "triple-beam": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
- "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==",
- "dev": true
- },
"trough": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
- "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz",
+ "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==",
"dev": true
},
"trouter": {
@@ -4078,327 +10049,235 @@
"integrity": "sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==",
"dev": true,
"requires": {
- "matchit": "1.0.8"
+ "matchit": "^1.0.0"
}
},
- "tslib": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
- "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
+ "ts-api-utils": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
+ "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+ "dev": true,
+ "requires": {}
+ },
+ "ts-node": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz",
+ "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==",
+ "dev": true,
+ "requires": {
+ "@cspotcode/source-map-support": "0.7.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "yn": "3.1.1"
+ },
+ "dependencies": {
+ "acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "dev": true
+ }
+ }
+ },
+ "type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "^1.2.1"
+ }
+ },
+ "type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true
},
- "tslint": {
- "version": "6.1.3",
- "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
- "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "7.10.4",
- "builtin-modules": "1.1.1",
- "chalk": "2.4.2",
- "commander": "2.20.0",
- "diff": "4.0.2",
- "glob": "7.1.6",
- "js-yaml": "3.13.1",
- "minimatch": "3.0.4",
- "mkdirp": "0.5.5",
- "resolve": "1.12.0",
- "semver": "5.5.0",
- "tslib": "1.13.0",
- "tsutils": "2.29.0"
- },
- "dependencies": {
- "minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
- "dev": true
- },
- "mkdirp": {
- "version": "0.5.5",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
- "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
- "dev": true,
- "requires": {
- "minimist": "1.2.5"
- }
- }
- }
- },
- "tslint-config-standard": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/tslint-config-standard/-/tslint-config-standard-9.0.0.tgz",
- "integrity": "sha512-CAw9J743RnPMemQV/XQ4YyNreC+A1NItACfkm+cBedrOkz6CQfwlnbKn8anUXBfoa4Zo4tjAhblRbsMNcSLfSw==",
- "dev": true,
- "requires": {
- "tslint-eslint-rules": "5.4.0"
- }
- },
- "tslint-eslint-rules": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz",
- "integrity": "sha512-WlSXE+J2vY/VPgIcqQuijMQiel+UtmXS+4nvK4ZzlDiqBfXse8FAvkNnTcYhnQyOTW5KFM+uRRGXxYhFpuBc6w==",
- "dev": true,
- "requires": {
- "doctrine": "0.7.2",
- "tslib": "1.9.0",
- "tsutils": "3.17.1"
- },
- "dependencies": {
- "tslib": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz",
- "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==",
- "dev": true
- },
- "tsutils": {
- "version": "3.17.1",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz",
- "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==",
- "dev": true,
- "requires": {
- "tslib": "1.9.0"
- }
- }
- }
- },
- "tsutils": {
- "version": "2.29.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
- "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
- "dev": true,
- "requires": {
- "tslib": "1.13.0"
- }
- },
- "tunnel-agent": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
- "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
- "requires": {
- "safe-buffer": "5.1.2"
- }
- },
- "tweetnacl": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
- "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
- "optional": true
- },
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"requires": {
"media-typer": "0.3.0",
- "mime-types": "2.1.24"
- },
- "dependencies": {
- "mime-db": {
- "version": "1.40.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
- "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
- },
- "mime-types": {
- "version": "2.1.24",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
- "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
- "requires": {
- "mime-db": "1.40.0"
- }
- }
+ "mime-types": "~2.1.24"
}
},
"typescript": {
- "version": "3.8.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
- "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
+ "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
"dev": true
},
"typescript-json-schema": {
- "version": "0.42.0",
- "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.42.0.tgz",
- "integrity": "sha512-9WO+lVmlph7Ecb7lPd9tU84XFUQh44kpAf3cWe/Ym4G5EKw/SS6XGpi1DZDthvxqkIdNSDlWi7FhKfxuIV/3yw==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.52.0.tgz",
+ "integrity": "sha512-3ZdHzx116gZ+D9LmMl5/+d1G3Rpt8baWngKzepYWHnXbAa8Winv64CmFRqLlMKneE1c40yugYDFcWdyX1FjGzQ==",
"dev": true,
"requires": {
- "@types/json-schema": "7.0.4",
- "glob": "7.1.6",
- "json-stable-stringify": "1.0.1",
- "typescript": "3.8.3",
- "yargs": "14.2.3"
- }
- },
- "uc.micro": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
- "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
- },
- "uglify-js": {
- "version": "2.8.29",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
- "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
- "requires": {
- "source-map": "0.5.7",
- "uglify-to-browserify": "1.0.2",
- "yargs": "3.10.0"
+ "@types/json-schema": "^7.0.9",
+ "@types/node": "^16.9.2",
+ "glob": "^7.1.7",
+ "safe-stable-stringify": "^2.2.0",
+ "ts-node": "^10.2.1",
+ "typescript": "~4.4.4",
+ "yargs": "^17.1.1"
},
"dependencies": {
- "cliui": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
- "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+ "typescript": {
+ "version": "4.4.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
+ "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
+ "dev": true
+ }
+ }
+ },
+ "umzug": {
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/umzug/-/umzug-3.8.1.tgz",
+ "integrity": "sha512-k0HjOc3b/s8vH24BUTvnaFiKhfWI9UQAGpqHDG+3866CGlBTB83Xs5wZ1io1mwYLj/GHvQ34AxKhbpYnWtkRJg==",
+ "requires": {
+ "@rushstack/ts-command-line": "^4.12.2",
+ "emittery": "^0.13.0",
+ "fast-glob": "^3.3.2",
+ "pony-cause": "^2.1.4",
+ "type-fest": "^4.0.0"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "4.23.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.23.0.tgz",
+ "integrity": "sha512-ZiBujro2ohr5+Z/hZWHESLz3g08BBdrdLMieYFULJO+tWc437sn8kQsWLJoZErY8alNhxre9K4p3GURAG11n+w=="
+ }
+ }
+ },
+ "underscore": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.2.tgz",
+ "integrity": "sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g=="
+ },
+ "unified": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.1.tgz",
+ "integrity": "sha512-v4ky1+6BN9X3pQrOdkFIPWAaeDsHPE1svRDxq7YpTc2plkIqFMwukfqM+l0ewpP9EfwARlt9pPFAeWYhHm8X9w==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "bail": "^2.0.0",
+ "extend": "^3.0.0",
+ "is-buffer": "^2.0.0",
+ "is-plain-obj": "^4.0.0",
+ "trough": "^2.0.0",
+ "vfile": "^5.0.0"
+ }
+ },
+ "unique-filename": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
+ "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
+ "optional": true,
+ "requires": {
+ "unique-slug": "^2.0.0"
+ }
+ },
+ "unique-slug": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz",
+ "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==",
+ "optional": true,
+ "requires": {
+ "imurmurhash": "^0.1.4"
+ }
+ },
+ "unist-util-inspect": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-inspect/-/unist-util-inspect-7.0.0.tgz",
+ "integrity": "sha512-2Utgv78I7PUu461Y9cdo+IUiiKSKpDV5CE/XD6vTj849a3xlpDAScvSJ6cQmtFBGgAmCn2wR7jLuXhpg1XLlJw==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0"
+ }
+ },
+ "unist-util-is": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz",
+ "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==",
+ "dev": true
+ },
+ "unist-util-stringify-position": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz",
+ "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0"
+ }
+ },
+ "unist-util-visit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.0.tgz",
+ "integrity": "sha512-n7lyhFKJfVZ9MnKtqbsqkQEk5P1KShj0+//V7mAcoI6bpbUjh3C/OG8HVD+pBihfh6Ovl01m8dkcv9HNqYajmQ==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^5.0.0",
+ "unist-util-visit-parents": "^5.0.0"
+ },
+ "dependencies": {
+ "unist-util-visit-parents": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.0.tgz",
+ "integrity": "sha512-y+QVLcY5eR/YVpqDsLf/xh9R3Q2Y4HxkZTp7ViLDU6WtJCEcPmRzW1gpdWDCDIqIlhuPDXOgttqPlykrHYDekg==",
+ "dev": true,
"requires": {
- "center-align": "0.1.3",
- "right-align": "0.1.3",
- "wordwrap": "0.0.2"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
- },
- "yargs": {
- "version": "3.10.0",
- "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
- "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
- "requires": {
- "camelcase": "1.2.1",
- "cliui": "2.1.0",
- "decamelize": "1.2.0",
- "window-size": "0.1.0"
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^5.0.0"
}
}
}
},
- "uglify-to-browserify": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
- "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
- "optional": true
- },
- "umzug": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz",
- "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==",
- "requires": {
- "bluebird": "3.7.2"
- }
- },
- "underscore": {
- "version": "1.7.0",
- "resolved": "http://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz",
- "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk="
- },
- "underscore.deep": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/underscore.deep/-/underscore.deep-0.5.1.tgz",
- "integrity": "sha1-ByZx9I1oc1w0Ij/P72PmnlJ2zCs="
- },
- "unherit": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
- "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
- "dev": true,
- "requires": {
- "inherits": "2.0.3",
- "xtend": "4.0.2"
- }
- },
- "unified": {
- "version": "8.4.2",
- "resolved": "https://registry.npmjs.org/unified/-/unified-8.4.2.tgz",
- "integrity": "sha512-JCrmN13jI4+h9UAyKEoGcDZV+i1E7BLFuG7OsaDvTXI5P0qhHX+vZO/kOhz9jn8HGENDKbwSeB0nVOg4gVStGA==",
- "dev": true,
- "requires": {
- "bail": "1.0.5",
- "extend": "3.0.2",
- "is-plain-obj": "2.1.0",
- "trough": "1.0.5",
- "vfile": "4.1.0"
- }
- },
- "unist-util-inspect": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/unist-util-inspect/-/unist-util-inspect-5.0.1.tgz",
- "integrity": "sha512-fPNWewS593JSmg49HbnE86BJKuBi1/nMWhDSccBvbARfxezEuJV85EaARR9/VplveiwCoLm2kWq+DhP8TBaDpw==",
- "dev": true,
- "requires": {
- "is-empty": "1.2.0"
- }
- },
- "unist-util-is": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
- "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==",
- "dev": true
- },
- "unist-util-remove-position": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz",
- "integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==",
- "dev": true,
- "requires": {
- "unist-util-visit": "1.4.1"
- }
- },
- "unist-util-stringify-position": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
- "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
- "dev": true,
- "requires": {
- "@types/unist": "2.0.3"
- }
- },
- "unist-util-visit": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz",
- "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==",
- "dev": true,
- "requires": {
- "unist-util-visit-parents": "2.1.2"
- }
- },
"unist-util-visit-parents": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz",
- "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz",
+ "integrity": "sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw==",
"dev": true,
"requires": {
- "unist-util-is": "3.0.0"
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^5.0.0"
}
},
"universalify": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
- "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
"dev": true
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
},
"uri-js": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
- "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"requires": {
- "punycode": "2.1.1"
- },
- "dependencies": {
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
- }
+ "punycode": "^2.1.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "optional": true
},
"utils-merge": {
"version": "1.0.1",
@@ -4406,408 +10285,174 @@
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"uuid": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
- "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
- "valid-data-url": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-2.0.0.tgz",
- "integrity": "sha512-dyCZnv3aCey7yfTgIqdZanKl7xWAEEKCbgmR7SKqyK6QT/Z07ROactrgD1eA37C69ODRj7rNOjzKWVPh0EUjBA=="
+ "uvu": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.3.tgz",
+ "integrity": "sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw==",
+ "dev": true,
+ "requires": {
+ "dequal": "^2.0.0",
+ "diff": "^5.0.0",
+ "kleur": "^4.0.3",
+ "sade": "^1.7.3"
+ },
+ "dependencies": {
+ "diff": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "dev": true
+ }
+ }
},
"validator": {
- "version": "10.11.0",
- "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz",
- "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw=="
+ "version": "13.7.0",
+ "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz",
+ "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw=="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
- "verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
- "requires": {
- "assert-plus": "1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "1.3.0"
- }
- },
"vfile": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.1.0.tgz",
- "integrity": "sha512-BaTPalregj++64xbGK6uIlsurN3BCRNM/P2Pg8HezlGzKd1O9PrwIac6bd9Pdx2uTb0QHoioZ+rXKolbVXEgJg==",
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.2.tgz",
+ "integrity": "sha512-w0PLIugRY3Crkgw89TeMvHCzqCs/zpreR31hl4D92y6SOE07+bfJe+dK5Q2akwS+i/c801kzjoOr9gMcTe6IAA==",
"dev": true,
"requires": {
- "@types/unist": "2.0.3",
- "is-buffer": "2.0.4",
- "replace-ext": "1.0.0",
- "unist-util-stringify-position": "2.0.3",
- "vfile-message": "2.0.4"
- },
- "dependencies": {
- "is-buffer": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
- "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
- "dev": true
- }
+ "@types/unist": "^2.0.0",
+ "is-buffer": "^2.0.0",
+ "unist-util-stringify-position": "^3.0.0",
+ "vfile-message": "^3.0.0"
}
},
- "vfile-location": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz",
- "integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA==",
- "dev": true
- },
"vfile-message": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
- "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz",
+ "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==",
"dev": true,
"requires": {
- "@types/unist": "2.0.3",
- "unist-util-stringify-position": "2.0.3"
- }
- },
- "void-elements": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
- "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w="
- },
- "web-resource-inliner": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-4.3.4.tgz",
- "integrity": "sha512-agVAgRhOOi4GVlvKK34oM23tDgH8390HfLnZY2HZl8OFBwKNvUJkH7t89AT2iluQP8w9VHAAKX6Z8EN7/9tqKA==",
- "requires": {
- "async": "3.2.0",
- "chalk": "2.4.2",
- "datauri": "2.0.0",
- "htmlparser2": "4.1.0",
- "lodash.unescape": "4.0.1",
- "request": "2.88.2",
- "safer-buffer": "2.1.2",
- "valid-data-url": "2.0.0",
- "xtend": "4.0.2"
- },
- "dependencies": {
- "aws4": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
- "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
- },
- "domelementtype": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
- "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
- },
- "domhandler": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.0.0.tgz",
- "integrity": "sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw==",
- "requires": {
- "domelementtype": "2.0.1"
- }
- },
- "domutils": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.0.0.tgz",
- "integrity": "sha512-n5SelJ1axbO636c2yUtOGia/IcJtVtlhQbFiVDBZHKV5ReJO1ViX7sFEemtuyoAnBxk5meNSYgA8V4s0271efg==",
- "requires": {
- "dom-serializer": "0.2.2",
- "domelementtype": "2.0.1",
- "domhandler": "3.0.0"
- }
- },
- "entities": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
- "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
- },
- "har-validator": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
- "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
- "requires": {
- "ajv": "6.12.0",
- "har-schema": "2.0.0"
- }
- },
- "htmlparser2": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
- "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
- "requires": {
- "domelementtype": "2.0.1",
- "domhandler": "3.0.0",
- "domutils": "2.0.0",
- "entities": "2.0.0"
- }
- },
- "oauth-sign": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
- "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
- },
- "request": {
- "version": "2.88.2",
- "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
- "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
- "requires": {
- "aws-sign2": "0.7.0",
- "aws4": "1.9.1",
- "caseless": "0.12.0",
- "combined-stream": "1.0.6",
- "extend": "3.0.2",
- "forever-agent": "0.6.1",
- "form-data": "2.3.2",
- "har-validator": "5.1.3",
- "http-signature": "1.2.0",
- "is-typedarray": "1.0.0",
- "isstream": "0.1.2",
- "json-stringify-safe": "5.0.1",
- "mime-types": "2.1.19",
- "oauth-sign": "0.9.0",
- "performance-now": "2.1.0",
- "qs": "6.5.2",
- "safe-buffer": "5.1.2",
- "tough-cookie": "2.5.0",
- "tunnel-agent": "0.6.0",
- "uuid": "3.3.2"
- }
- },
- "tough-cookie": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
- "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
- "requires": {
- "psl": "1.8.0",
- "punycode": "2.1.1"
- }
- }
+ "@types/unist": "^2.0.0",
+ "unist-util-stringify-position": "^3.0.0"
}
},
"which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "devOptional": true,
"requires": {
- "isexe": "2.0.0"
+ "isexe": "^2.0.0"
}
},
- "which-module": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
- "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
- "dev": true
- },
"wide-align": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
- "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
+ "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
"optional": true,
"requires": {
- "string-width": "1.0.2"
- }
- },
- "window-size": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
- "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0="
- },
- "winston-transport": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz",
- "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==",
- "dev": true,
- "requires": {
- "readable-stream": "2.3.6",
- "triple-beam": "1.3.0"
- }
- },
- "with": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/with/-/with-5.1.1.tgz",
- "integrity": "sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4=",
- "requires": {
- "acorn": "3.3.0",
- "acorn-globals": "3.1.0"
+ "string-width": "^1.0.2 || 2 || 3 || 4"
}
},
"wkx": {
- "version": "0.4.8",
- "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.8.tgz",
- "integrity": "sha512-ikPXMM9IR/gy/LwiOSqWlSL3X/J5uk9EO2hHNRXS41eTLXaUFEVw9fn/593jW/tE5tedNg8YjT5HkCa4FqQZyQ==",
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz",
+ "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==",
"requires": {
- "@types/node": "12.12.32"
+ "@types/node": "*"
}
},
- "wordwrap": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
- "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8="
- },
"wrap-ansi": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
- "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"requires": {
- "ansi-styles": "3.2.1",
- "string-width": "3.1.0",
- "strip-ansi": "5.2.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
- "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
- "dev": true
- },
- "string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
- "dev": true,
- "requires": {
- "emoji-regex": "7.0.3",
- "is-fullwidth-code-point": "2.0.0",
- "strip-ansi": "5.2.0"
- }
- },
- "strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "dev": true,
- "requires": {
- "ansi-regex": "4.1.0"
- }
- }
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "devOptional": true
},
"ws": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.0.tgz",
- "integrity": "sha512-+SqNqFbwTm/0DC18KYzIsMTnEWpLwJsiasW/O17la4iDRRIO9uaHbvKiAS3AHgTiuuWerK/brj4O6MYZkei9xg==",
- "requires": {
- "async-limiter": "1.0.1"
- }
- },
- "xmlhttprequest-ssl": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
- "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4="
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+ "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
+ "requires": {}
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
},
+ "xxhashjs": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz",
+ "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==",
+ "dev": true,
+ "requires": {
+ "cuint": "^0.2.2"
+ }
+ },
"y18n": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
- "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true
},
"yallist": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
- "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"yargs": {
- "version": "14.2.3",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz",
- "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==",
+ "version": "17.3.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz",
+ "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==",
"dev": true,
"requires": {
- "cliui": "5.0.0",
- "decamelize": "1.2.0",
- "find-up": "3.0.0",
- "get-caller-file": "2.0.5",
- "require-directory": "2.1.1",
- "require-main-filename": "2.0.0",
- "set-blocking": "2.0.0",
- "string-width": "3.1.0",
- "which-module": "2.0.0",
- "y18n": "4.0.0",
- "yargs-parser": "15.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
- "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
- "dev": true
- },
- "string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
- "dev": true,
- "requires": {
- "emoji-regex": "7.0.3",
- "is-fullwidth-code-point": "2.0.0",
- "strip-ansi": "5.2.0"
- }
- },
- "strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "dev": true,
- "requires": {
- "ansi-regex": "4.1.0"
- }
- }
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.0.0"
}
},
"yargs-parser": {
- "version": "15.0.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz",
- "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==",
- "dev": true,
- "requires": {
- "camelcase": "5.3.1",
- "decamelize": "1.2.0"
- },
- "dependencies": {
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true
- }
- }
+ "version": "21.0.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz",
+ "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==",
+ "dev": true
},
- "yeast": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
- "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
+ "yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true
+ },
+ "yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true
+ },
+ "zwitch": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.2.tgz",
+ "integrity": "sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA==",
+ "dev": true
}
}
}
diff --git a/package.json b/package.json
index 5a4bee4..6b88f53 100644
--- a/package.json
+++ b/package.json
@@ -5,9 +5,9 @@
"description": "",
"scripts": {
"start": "node ./build/index.js",
- "test": "echo \"Error: no test specified\" && exit 1",
- "lint": "tslint --project .",
- "lint:fix": "tslint --project . --fix",
+ "test": "node scripts/test-launch-with-different-databases.js",
+ "lint": "eslint . --ext .js,.jsx,.ts,.tsx",
+ "lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"build": "npm run build:clean && npm run build:json && npm run build:ts && npm run lint && npm run build:doc",
"build:clean": "rimraf build",
"build:json": "node ./scripts/build-schemas.js",
@@ -29,44 +29,42 @@
},
"homepage": "https://gitlab.com/timelimit.io/timelimit-server-2018#README",
"devDependencies": {
- "@adobe/jsonschema2md": "^4.1.2",
+ "@adobe/jsonschema2md": "^7.0.0",
"@types/basic-auth": "^1.1.3",
"@types/body-parser": "^1.19.0",
- "@types/email-templates": "^6.0.2",
- "@types/express": "^4.17.3",
- "@types/http-errors": "^1.6.3",
- "@types/lodash": "^4.14.149",
- "@types/node": "^12.12.32",
- "@types/socket.io": "^2.1.4",
- "@types/tokgen": "^1.0.0",
- "@types/umzug": "^2.2.3",
+ "@types/ejs": "^3.1.0",
+ "@types/express": "^4.17.9",
+ "@types/http-errors": "^1.8.0",
+ "@types/lodash": "^4.14.166",
+ "@types/node": "^16.11.59",
+ "@types/nodemailer": "^6.4.4",
+ "@typescript-eslint/eslint-plugin": "^7.18.0",
+ "@typescript-eslint/parser": "^7.18.0",
+ "eslint": "^8.7.0",
"rimraf": "^3.0.2",
- "tslint": "^6.1.3",
- "tslint-config-standard": "^9.0.0",
- "typescript": "^3.8.3",
- "typescript-json-schema": "^0.42.0"
+ "typescript": "^5.5.4",
+ "typescript-json-schema": "^0.52.0"
},
"dependencies": {
- "ajv": "^6.12.0",
+ "ajv": "^7.0.2",
"basic-auth": "^2.0.1",
"body-parser": "^1.19.0",
- "ejs": "^2.7.4",
+ "ejs": "^3.1.5",
"email-addresses": "^3.1.0",
- "email-templates": "^7.0.4",
"express": "^4.17.1",
- "http-errors": "^1.7.3",
- "iab_verifier": "^0.1.2",
- "lodash": "^4.17.19",
- "mariadb": "^2.3.1",
- "pg": "^7.18.2",
+ "http-errors": "^1.8.0",
+ "jose": "^4.9.3",
+ "lodash": "^4.17.21",
+ "mariadb": "^2.5.2",
+ "nodemailer": "^6.7.2",
+ "pg": "^8.5.1",
"pg-hstore": "^2.3.3",
- "rate-limiter-flexible": "^2.1.3",
- "sequelize": "^5.21.5",
- "socket.io": "^2.3.0",
- "tokgen": "^1.0.0",
- "umzug": "^2.3.0"
+ "rate-limiter-flexible": "^2.1.15",
+ "sequelize": "^6.25.5",
+ "socket.io": "^4.0.1",
+ "umzug": "^3.8.1"
},
"optionalDependencies": {
- "sqlite3": "^4.0.6"
+ "sqlite3": "^5.0.0"
}
}
diff --git a/scripts/build-schemas.js b/scripts/build-schemas.js
index c70d53f..8c42121 100644
--- a/scripts/build-schemas.js
+++ b/scripts/build-schemas.js
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2024 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -29,7 +29,6 @@ const types = [
'CreateFamilyByMailTokenRequest',
'SignIntoFamilyRequest',
'RecoverParentPasswordRequest',
- 'CanRecoverPasswordRequest',
'RegisterChildDeviceRequest',
'SerializedParentAction',
'SerializedAppLogicAction',
@@ -40,9 +39,12 @@ const types = [
'LinkParentMailAddressRequest',
'UpdatePrimaryDeviceRequest',
'RemoveDeviceRequest',
+ 'RequestIdentityTokenRequest',
'RequestWithAuthToken',
'SendMailLoginCodeRequest',
- 'SignInByMailCodeRequest'
+ 'SignInByMailCodeRequest',
+ 'IdentityTokenPayload',
+ 'DeleteAccountPayload',
]
const docOnlyTypes = [
@@ -56,12 +58,14 @@ const allTypes = [
const settings = {
required: true,
- noExtraProps: true
+ noExtraProps: true,
+ // otherwise it finds errors in dependencies that we don't care about
+ ignoreErrors: true
};
const compilerOptions = {
strictNullChecks: true,
- lib: ['es2015']
+ lib: ['es2015', 'dom']
}
// optionally pass a base path
@@ -95,7 +99,7 @@ allTypes.forEach((type) => {
output += '// tslint:disable \n'
output += 'import { ' + types.join(', ') + ' } from \'./schema\'\n'
-output += 'const Ajv = require(\'ajv\')\n'
+output += 'import Ajv from \'ajv\'\n'
output += 'const ajv = new Ajv()\n'
output += '\n'
output += 'const definitions = ' + JSON.stringify(definitions, null, 2) + '\n\n'
@@ -116,7 +120,7 @@ types.forEach((type) => {
const functionBody = 'ajv.compile(' + schemaString + ')'
const functionName = 'is' + type.substr(0, 1).toUpperCase() + type.substr(1)
- output += 'export const ' + functionName + ': (value: object) => value is ' + type + ' = ' + functionBody + '\n'
+ output += 'export const ' + functionName + ': (value: unknown) => value is ' + type + ' = ' + functionBody + '\n'
})
allTypes.forEach((type) => {
diff --git a/scripts/test-launch-with-different-databases.js b/scripts/test-launch-with-different-databases.js
new file mode 100644
index 0000000..1880bbe
--- /dev/null
+++ b/scripts/test-launch-with-different-databases.js
@@ -0,0 +1,55 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+const { databaseLaunchers } = require('./util/database')
+const { startMainApp } = require('./util/mainapp.js')
+
+// use export PATH="$PATH:/usr/lib/postgresql/11/bin"
+// if the postgres binaries are not in the path
+
+async function main() {
+ let log = ''
+
+ for (const launcher of databaseLaunchers) {
+ const database = await launcher()
+
+ console.log('Test with ' + database.type)
+
+ try {
+ const task = await startMainApp({
+ DATABASE_URL: database.connectionUrl
+ })
+
+ console.log('test successfull')
+ log += 'Worked with ' + database.type + '\n'
+
+ task.shutdown()
+ } catch (ex) {
+ log += 'Failure with ' + database.type + '\n'
+ console.warn('test failed', ex)
+ }
+
+ database.shutdown()
+ }
+
+ console.log('\nRESULTS\n\n' + log)
+ process.exit(0)
+}
+
+main().catch((ex) => {
+ console.warn(ex)
+})
diff --git a/scripts/util/database/helper.js b/scripts/util/database/helper.js
new file mode 100644
index 0000000..f58d31e
--- /dev/null
+++ b/scripts/util/database/helper.js
@@ -0,0 +1,22 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+const { resolve } = require('path')
+
+const tempDir = resolve(__dirname, '../../../tempdb')
+
+module.exports = { tempDir }
diff --git a/scripts/util/database/index.js b/scripts/util/database/index.js
new file mode 100644
index 0000000..1a27cdd
--- /dev/null
+++ b/scripts/util/database/index.js
@@ -0,0 +1,25 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+const { startPostgres } = require('./postgres.js')
+const { startMariadb } = require('./mariadb.js')
+const { startSqlite } = require('./sqlite.js')
+
+module.exports = {
+ startPostgres,
+ databaseLaunchers: [ startMariadb, startPostgres, startSqlite ]
+}
diff --git a/scripts/util/database/mariadb.js b/scripts/util/database/mariadb.js
new file mode 100644
index 0000000..e75a8a8
--- /dev/null
+++ b/scripts/util/database/mariadb.js
@@ -0,0 +1,82 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+const { resolve } = require('path')
+const { spawn } = require('child_process')
+const { tempDir } = require('./helper.js')
+const { generateShortToken, generateToken } = require('../token.js')
+const { rimrafAsync, mkdirAsync, readFileAsync, writeFileAsync } = require('../filesystem.js')
+const { spawnAsync } = require('../process.js')
+const { sleep } = require('../sleep.js')
+
+async function startMariadb() {
+ try { await mkdirAsync(tempDir) } catch (ex) {/* ignore */}
+
+ const instanceDir = resolve(tempDir, generateShortToken())
+ const dataDir = resolve(instanceDir, 'data')
+ const socketPath = resolve(instanceDir, 'socket')
+
+ await rimrafAsync(instanceDir)
+ await mkdirAsync(instanceDir); await mkdirAsync(dataDir)
+
+ await spawnAsync('mysql_install_db', ['--datadir=' + dataDir, '--user=' + process.env.USER], { stdio: 'inherit' })
+
+ const task = await spawn('mysqld_safe', ['--no-defaults', '--datadir=' + dataDir, '--socket=' + socketPath, '--skip-networking'], { stdio: 'inherit' })
+ task.on('exit', () => rimrafAsync(instanceDir))
+
+ for (let i = 0; i < 100; i++) {
+ const { status } = await spawnAsync('mysqladmin', ['ping', '-S', socketPath])
+
+ if (status === 0) break
+
+ await sleep(100)
+ }
+
+ const database = generateShortToken()
+ const username = generateShortToken()
+ const password = generateToken()
+
+ const commands = [
+ 'CREATE DATABASE `' + database + '` DEFAULT CHARACTER SET `utf8mb4` COLLATE `utf8mb4_bin`',
+ // all users of the system can see this password because it is passed as command
+ // line parameter - don't do this for anything important
+ 'CREATE USER `' + username + '`@localhost IDENTIFIED BY \'' + password + '\'',
+ 'GRANT ALL PRIVILEGES ON `' + database + '`.* TO `' + username + '`@localhost'
+ ]
+
+ for (command of commands) {
+ console.log(command)
+ await spawnAsync('mysql', ['-S', socketPath, '-u', 'root', '-e', command], { stdio: 'inherit' })
+ }
+
+ return {
+ shutdown: () => {
+ spawnAsync('mysql', ['-S', socketPath, '-u', 'root', '-e', 'SHUTDOWN;'], { stdio: 'inherit' }).catch((ex) => {
+ console.warn(ex)
+ })
+ },
+ socketPath,
+ dataDir,
+ database,
+ username,
+ password,
+ connectionUrl: 'mariadb://' + username + ':' + password + '@localhost/' + database + '?socketPath=' + encodeURIComponent(socketPath),
+ type: 'mariadb'
+ }
+}
+
+module.exports = { startMariadb }
diff --git a/scripts/util/database/postgres.js b/scripts/util/database/postgres.js
new file mode 100644
index 0000000..0a5c20d
--- /dev/null
+++ b/scripts/util/database/postgres.js
@@ -0,0 +1,75 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+const { resolve } = require('path')
+const { spawn } = require('child_process')
+const { tempDir } = require('./helper.js')
+const { generateShortToken, generateToken } = require('../token.js')
+const { rimrafAsync, mkdirAsync, readFileAsync, writeFileAsync } = require('../filesystem.js')
+const { spawnAsync } = require('../process.js')
+const { sleep } = require('../sleep.js')
+
+async function startPostgres() {
+ try { await mkdirAsync(tempDir) } catch (ex) {/* ignore */}
+
+ const instanceDir = resolve(tempDir, generateShortToken())
+ const dataDir = resolve(instanceDir, 'data')
+ const socketDir = resolve(instanceDir, 'socket')
+
+ await rimrafAsync(instanceDir)
+ await mkdirAsync(instanceDir); await mkdirAsync(dataDir); await mkdirAsync(socketDir)
+
+ await spawnAsync('initdb', ['--locale=en_US.UTF-8', '-E', ' UTF8', '-D', dataDir], { stdio: 'inherit' })
+
+ const configFilePath = resolve(dataDir, 'postgresql.conf')
+ const configFileContent = (await readFileAsync(configFilePath)) + '\n'
+ + 'unix_socket_directories = \'' + socketDir + '\'' + '\n'
+ + 'listen_addresses = \'\' # do not listen using TCP'
+
+ await writeFileAsync(configFilePath, configFileContent)
+
+ const task = spawn('postgres', ['-D', dataDir], { stdio: 'inherit' })
+ task.on('exit', () => rimrafAsync(instanceDir))
+
+ for (let i = 0; i < 100; i++) {
+ const { status } = await spawnAsync('pg_isready', ['-h', socketDir])
+
+ if (status === 0) break
+
+ await sleep(100)
+ }
+
+ const database = generateShortToken()
+ const username = generateShortToken()
+ const password = generateToken() // this database accepts anything
+
+ await spawnAsync('createuser', ['-h', socketDir, username], { stdio: 'inherit' })
+ await spawnAsync('createdb', ['-h', socketDir, database], { stdio: 'inherit' })
+
+ return {
+ shutdown: () => task.kill('SIGINT'),
+ socketDir,
+ dataDir,
+ database,
+ username,
+ password,
+ connectionUrl: 'postgres://' + username + ':' + password + '@localhost/' + database + '?host=' + encodeURIComponent(socketDir),
+ type: 'postgres'
+ }
+}
+
+module.exports = { startPostgres }
diff --git a/scripts/util/database/sqlite.js b/scripts/util/database/sqlite.js
new file mode 100644
index 0000000..081f98d
--- /dev/null
+++ b/scripts/util/database/sqlite.js
@@ -0,0 +1,42 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+const { resolve } = require('path')
+const { spawn } = require('child_process')
+const { tempDir } = require('./helper.js')
+const { generateShortToken, generateToken } = require('../token.js')
+const { rimrafAsync, mkdirAsync, readFileAsync, writeFileAsync } = require('../filesystem.js')
+const { spawnAsync } = require('../process.js')
+const { sleep } = require('../sleep.js')
+
+async function startSqlite() {
+ try { await mkdirAsync(tempDir) } catch (ex) {/* ignore */}
+
+ const instanceDir = resolve(tempDir, generateShortToken())
+
+ await rimrafAsync(instanceDir)
+ await mkdirAsync(instanceDir)
+
+ return {
+ shutdown: () => rimrafAsync(instanceDir),
+ instanceDir,
+ connectionUrl: 'sqlite:///' + instanceDir + '/test.db',
+ type: 'sqlite'
+ }
+}
+
+module.exports = { startSqlite }
diff --git a/scripts/util/filesystem.js b/scripts/util/filesystem.js
new file mode 100644
index 0000000..94efbe6
--- /dev/null
+++ b/scripts/util/filesystem.js
@@ -0,0 +1,57 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+const rimraf = require('rimraf')
+const { mkdir, readFile, writeFile } = require('fs')
+
+function mkdirAsync(path) {
+ return new Promise((resolve, reject) => {
+ mkdir(path, (err) => {
+ if (err) reject(err)
+ else resolve()
+ })
+ })
+}
+
+function rimrafAsync(path) {
+ return new Promise((resolve, reject) => {
+ rimraf(path, (err) => {
+ if (err) reject(err)
+ else resolve()
+ })
+ })
+}
+
+function readFileAsync(path) {
+ return new Promise((resolve, reject) => {
+ readFile(path, (err, res) => {
+ if (err) reject(err)
+ else resolve(res)
+ })
+ })
+}
+
+function writeFileAsync(path, content) {
+ return new Promise((resolve, reject) => {
+ writeFile(path, content, (err) => {
+ if (err) reject(err)
+ else resolve()
+ })
+ })
+}
+
+module.exports = { mkdirAsync, rimrafAsync, readFileAsync, writeFileAsync }
diff --git a/scripts/util/mainapp.js b/scripts/util/mainapp.js
new file mode 100644
index 0000000..0d141f9
--- /dev/null
+++ b/scripts/util/mainapp.js
@@ -0,0 +1,51 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+const { spawn } = require('child_process')
+const { resolve } = require('path')
+
+function startMainApp(env) {
+ const initPath = resolve(__dirname, '../../build/index.js')
+
+ return new Promise((resolve, reject) => {
+ const task = spawn('node', [initPath], {
+ stdio: ['inherit', 'pipe', 'inherit'],
+ env: { ...process.env, PORT: 0 /* random port */, ...env }
+ })
+
+ task.on('exit', () => reject(new Error('task terminated too early')))
+ task.on('error', (ex) => reject(ex))
+
+ task.stdout.on('data', (data) => {
+ if (data.toString('utf8').split('\n').indexOf('ready') !== -1) resolve(task)
+
+ process.stdout.write(data)
+ })
+
+ setTimeout(() => {
+ reject(new Error('timeout'))
+
+ task.kill('SIGINT')
+ }, 1000 * 30)
+ }).then((task) => {
+ return {
+ shutdown: () => task.kill('SIGINT')
+ }
+ })
+}
+
+module.exports = { startMainApp }
diff --git a/scripts/util/process.js b/scripts/util/process.js
new file mode 100644
index 0000000..6c2d5ea
--- /dev/null
+++ b/scripts/util/process.js
@@ -0,0 +1,29 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+const { spawn } = require('child_process')
+
+function spawnAsync(command, args, options) {
+ return new Promise((resolve, reject) => {
+ const task = spawn(command, args, options)
+
+ task.on('error', (ex) => reject(ex))
+ task.on('exit', (status) => resolve({ status }))
+ })
+}
+
+module.exports = { spawnAsync }
diff --git a/scripts/util/sleep.js b/scripts/util/sleep.js
new file mode 100644
index 0000000..5e7632b
--- /dev/null
+++ b/scripts/util/sleep.js
@@ -0,0 +1,24 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+function sleep(delay) {
+ return new Promise((resolve, reject) => {
+ setTimeout(() => resolve(), delay)
+ })
+}
+
+module.exports = { sleep }
diff --git a/scripts/util/token.js b/scripts/util/token.js
new file mode 100644
index 0000000..6140abd
--- /dev/null
+++ b/scripts/util/token.js
@@ -0,0 +1,23 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+const { randomBytes } = require('crypto')
+
+function generateToken() { return randomBytes(32).toString('hex') }
+function generateShortToken() { return randomBytes(8).toString('hex') }
+
+module.exports = { generateToken, generateShortToken }
diff --git a/src/action/addu2fkey.ts b/src/action/addu2fkey.ts
new file mode 100644
index 0000000..09c8c76
--- /dev/null
+++ b/src/action/addu2fkey.ts
@@ -0,0 +1,52 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { ParentAction } from './basetypes'
+import { throwOutOfRange } from './meta/util'
+
+const actionType = 'AddParentU2fKey'
+
+export class AddParentU2fKeyAction extends ParentAction {
+ readonly keyHandle: Buffer
+ readonly publicKey: Buffer
+
+ constructor ({ keyHandle, publicKey }: {
+ keyHandle: Buffer
+ publicKey: Buffer
+ }) {
+ super()
+
+ if (keyHandle.length > 2048) throwOutOfRange({ actionType, field: 'keyHandle', value: keyHandle.length })
+ if (publicKey.length > 2048) throwOutOfRange({ actionType, field: 'publicKey', value: publicKey.length })
+
+ this.keyHandle = keyHandle
+ this.publicKey = publicKey
+ }
+
+ static parse = ({ keyHandle, publicKey }: SerializedAddParentU2fKeyAction) => (
+ new AddParentU2fKeyAction({
+ keyHandle: Buffer.from(keyHandle, 'base64'),
+ publicKey: Buffer.from(publicKey, 'base64')
+ })
+ )
+}
+
+export interface SerializedAddParentU2fKeyAction {
+ type: 'ADD_PARENT_U2F'
+ keyHandle: string
+ publicKey: string
+}
diff --git a/src/action/adduser.ts b/src/action/adduser.ts
index 2339b1b..abf4e26 100644
--- a/src/action/adduser.ts
+++ b/src/action/adduser.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-import { assertParentPasswordValid, ParentPassword, ParentPasswordValidationException } from '../api/schema'
+import { assertParentPasswordValid, EncryptableParentPassword, ParentPasswordValidationException } from '../api/schema'
import { ParentAction } from './basetypes'
import { InvalidActionParameterException } from './meta/exception'
import { assertIdWithinFamily } from './meta/util'
@@ -26,14 +26,14 @@ export class AddUserAction extends ParentAction {
readonly userId: string
readonly name: string
readonly userType: 'parent' | 'child'
- readonly password?: ParentPassword
+ readonly password?: EncryptableParentPassword
readonly timeZone: string
constructor ({ userId, name, userType, password, timeZone }: {
userId: string
name: string
userType: 'parent' | 'child'
- password?: ParentPassword
+ password?: EncryptableParentPassword
timeZone: string
}) {
super()
@@ -85,6 +85,6 @@ export interface SerializedAddUserAction {
name: string
userType: 'parent' | 'child'
userId: string
- password?: ParentPassword
+ password?: EncryptableParentPassword
timeZone: string
}
diff --git a/src/action/childchangepassword.ts b/src/action/childchangepassword.ts
index cb36999..ca30aaf 100644
--- a/src/action/childchangepassword.ts
+++ b/src/action/childchangepassword.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,17 +15,17 @@
* along with this program. If not, see .
*/
-import { assertParentPasswordValid, ParentPassword, ParentPasswordValidationException } from '../api/schema'
+import { assertParentPasswordValid, EncryptableParentPassword, ParentPasswordValidationException } from '../api/schema'
import { ChildAction } from './basetypes'
import { InvalidActionParameterException } from './meta/exception'
const actionType = 'ChildChangePasswordAction'
export class ChildChangePasswordAction extends ChildAction {
- readonly password: ParentPassword
+ readonly password: EncryptableParentPassword
constructor ({ password }: {
- password: ParentPassword
+ password: EncryptableParentPassword
}) {
super()
@@ -50,5 +50,5 @@ export class ChildChangePasswordAction extends ChildAction {
export interface SerializedChildChangePasswordAction {
type: 'CHILD_CHANGE_PASSWORD'
- password: ParentPassword
+ password: EncryptableParentPassword
}
diff --git a/src/action/childsignin.ts b/src/action/childsignin.ts
index 5fe208f..f9a8423 100644
--- a/src/action/childsignin.ts
+++ b/src/action/childsignin.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -18,13 +18,11 @@
import { ChildAction } from './basetypes'
export class ChildSignInAction extends ChildAction {
+ static instance = new ChildSignInAction()
+
constructor () {
super()
}
-
- static parse = (_: SerializedChildSignInAction) => (
- new ChildSignInAction()
- )
}
export interface SerializedChildSignInAction {
diff --git a/src/action/finishkeyrequest.ts b/src/action/finishkeyrequest.ts
new file mode 100644
index 0000000..2558eaa
--- /dev/null
+++ b/src/action/finishkeyrequest.ts
@@ -0,0 +1,44 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { AppLogicAction } from './basetypes'
+import { assertSafeInteger } from './meta/util'
+
+const actionType = 'FinishKeyRequestAction'
+
+export class FinishKeyRequestAction extends AppLogicAction {
+ readonly deviceSequenceNumber: number
+
+ constructor ({ deviceSequenceNumber }: { deviceSequenceNumber: number }) {
+ super()
+
+ assertSafeInteger({ value: deviceSequenceNumber, field: 'deviceSequenceNumber', actionType })
+
+ this.deviceSequenceNumber = deviceSequenceNumber
+ }
+
+ static parse = ({ dsn }: SerializedFinishKeyRequestAction) => (
+ new FinishKeyRequestAction({
+ deviceSequenceNumber: dsn,
+ })
+ )
+}
+
+export interface SerializedFinishKeyRequestAction {
+ type: 'FINISH_KEY_REQUEST'
+ dsn: number
+}
diff --git a/src/action/forcesync.ts b/src/action/forcesync.ts
index f0bd48e..123fb7c 100644
--- a/src/action/forcesync.ts
+++ b/src/action/forcesync.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -23,8 +23,6 @@ export class ForceSyncAction extends AppLogicAction {
private constructor () {
super()
}
-
- static parse = (_: SerializedForceSyncAction) => ForceSyncAction.instance
}
export interface SerializedForceSyncAction {
diff --git a/src/action/ignoremanipulation.ts b/src/action/ignoremanipulation.ts
index ce7d79b..638c849 100644
--- a/src/action/ignoremanipulation.ts
+++ b/src/action/ignoremanipulation.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -33,11 +33,13 @@ export class IgnoreManipulationAction extends ParentAction {
readonly ignoreDidReboot: boolean
readonly ignoreHadManipulation: boolean
readonly ignoreHadManipulationFlags: number
+ readonly ignoreManipulationFlags: number
constructor ({
deviceId, ignoreDeviceAdminManipulation, ignoreDeviceAdminManipulationAttempt,
ignoreAppDowngrade, ignoreNotificationAccessManipulation, ignoreUsageStatsAccessManipulation,
- ignoreOverlayPermissionManipulation, ignoreAccessibilityServiceManipulation, ignoreDidReboot, ignoreHadManipulation, ignoreHadManipulationFlags
+ ignoreOverlayPermissionManipulation, ignoreAccessibilityServiceManipulation, ignoreDidReboot,
+ ignoreHadManipulation, ignoreHadManipulationFlags, ignoreManipulationFlags
}: {
deviceId: string
ignoreDeviceAdminManipulation: boolean
@@ -50,6 +52,7 @@ export class IgnoreManipulationAction extends ParentAction {
ignoreDidReboot: boolean
ignoreHadManipulation: boolean
ignoreHadManipulationFlags: number
+ ignoreManipulationFlags: number
}) {
super()
@@ -63,6 +66,8 @@ export class IgnoreManipulationAction extends ParentAction {
throwOutOfRange({ actionType, field: 'ignoreHadManipulationFlags', value: ignoreHadManipulationFlags })
}
+ assertSafeInteger({ actionType, field: 'ignoreManipulationFlags', value: ignoreManipulationFlags })
+
this.deviceId = deviceId
this.ignoreDeviceAdminManipulation = ignoreDeviceAdminManipulation
this.ignoreDeviceAdminManipulationAttempt = ignoreDeviceAdminManipulationAttempt
@@ -74,9 +79,14 @@ export class IgnoreManipulationAction extends ParentAction {
this.ignoreDidReboot = ignoreDidReboot
this.ignoreHadManipulation = ignoreHadManipulation
this.ignoreHadManipulationFlags = ignoreHadManipulationFlags
+ this.ignoreManipulationFlags = ignoreManipulationFlags
}
- static parse = ({ deviceId, admin, adminA, downgrade, notification, usageStats, overlay, accessibilityService, reboot, hadManipulation, ignoreHadManipulationFlags }: SerializedIgnoreManipulationAction) => (
+ static parse = ({
+ deviceId, admin, adminA, downgrade, notification, usageStats, overlay,
+ accessibilityService, reboot, hadManipulation, ignoreHadManipulationFlags,
+ ignoreManipulationFlags
+ }: SerializedIgnoreManipulationAction) => (
new IgnoreManipulationAction({
deviceId,
ignoreDeviceAdminManipulation: admin,
@@ -88,7 +98,8 @@ export class IgnoreManipulationAction extends ParentAction {
ignoreAccessibilityServiceManipulation: !!accessibilityService,
ignoreDidReboot: !!reboot,
ignoreHadManipulation: hadManipulation,
- ignoreHadManipulationFlags: ignoreHadManipulationFlags || 0
+ ignoreHadManipulationFlags: ignoreHadManipulationFlags || 0,
+ ignoreManipulationFlags: ignoreManipulationFlags || 0
})
)
}
@@ -107,4 +118,5 @@ export interface SerializedIgnoreManipulationAction {
overlay?: boolean
accessibilityService?: boolean
ignoreHadManipulationFlags?: number
+ ignoreManipulationFlags?: number
}
diff --git a/src/action/index.ts b/src/action/index.ts
index b3003a8..d47785d 100644
--- a/src/action/index.ts
+++ b/src/action/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -21,6 +21,7 @@ export { AddCategoryAppsAction } from './addcategoryapps'
export { AddCategoryNetworkIdAction } from './addcategorynetworkid'
export { AddUserAction } from './adduser'
export { AddInstalledAppsAction } from './addinstalledapps'
+export { AddParentU2fKeyAction } from './addu2fkey'
export { AddUsedTimeAction } from './addusedtime'
export { AddUsedTimeActionVersion2 } from './addusedtime2'
export { ChangeParentPasswordAction } from './changeparentpassword'
@@ -30,15 +31,18 @@ export { CreateCategoryAction } from './createcategory'
export { CreateTimeLimitRuleAction } from './createtimelimitrule'
export { DeleteCategoryAction } from './deletecategory'
export { DeleteTimeLimitRuleAction } from './deletetimelimitrule'
+export { FinishKeyRequestAction } from './finishkeyrequest'
export { ForceSyncAction } from './forcesync'
export { IgnoreManipulationAction } from './ignoremanipulation'
export { IncrementCategoryExtraTimeAction } from './incrementcategoryextratime'
export { RemoveCategoryAppsAction } from './removecategoryapps'
export { RemoveInstalledAppsAction } from './removeinstalledapps'
+export { RemoveParentU2fKeyAction } from './removeu2fkey'
export { RemoveUserAction } from './removeuser'
export { ResetCategoryNetworkIdsAction } from './resetcategorynetworkids'
export { RenameChildAction } from './renamechild'
-export { ResetParentBlockedTimesAction } from './resetparentblockedtimes'
+export { ReplyToKeyRequestAction } from './replytokeyrequest'
+export { ReportU2fLoginAction } from './reportu2flogin'
export { SetCategoryExtraTimeAction } from './setcategoryextratime'
export { SetCategoryForUnassignedAppsAction } from './setcategoryforunassignedapps'
export { SetChildPasswordAction } from './setchildpassword'
@@ -59,6 +63,7 @@ export { UpdateCategoryBatteryLimitAction } from './updatecategorybatterylimit'
export { UpdateCategoryBlockAllNotificationsAction } from './updatecategoryblockallnotifications'
export { UpdateCategoryBlockedTimesAction } from './updatecategoryblockedtimes'
export { UpdateCategoryDisableLimitsAction } from './updatecategorydisablelimits'
+export { UpdateCategoryFlagsAction } from './updatecategoryflags'
export { UpdateCategorySortingAction } from './updatecategorysorting'
export { UpdateCategoryTemporarilyBlockedAction } from './updatecategorytemporarilyblocked'
export { UpdateCategoryTimeWarningsAction } from './updatecategorytimewarnings'
@@ -66,8 +71,8 @@ export { UpdateCategoryTitleAction } from './updatecategorytitle'
export { UpdateDeviceNameAction } from './updatedevicename'
export { UpdateDeviceStatusAction } from './updatedevicestatus'
export { UpdateEnableActivityLevelBlockingAction } from './updateenableactivitylevelblocking'
+export { UpdateInstalledAppsAction } from './updateinstalledapps'
export { UpdateNetworkTimeVerificationAction } from './updatenetworktimeverification'
-export { UpdateParentBlockedTimesAction } from './updateparentblockedtimes'
export { UpdateParentNotificationFlagsAction } from './updateparentnotificationflags'
export { UpdateTimelimitRuleAction } from './updatetimelimitrule'
export { UpdateUserFlagsAction } from './updateuserflags'
@@ -76,3 +81,6 @@ export { MarkTaskPendingAction } from './marktaskpendingaction'
export { DeleteChildTaskAction } from './deletechildtaskaction'
export { UpdateChildTaskAction } from './updatechildtaskaction'
export { ReviewChildTaskAction } from './reviewchildtaskaction'
+export { UpdateUserLimitLoginPreBlockDuration } from './updateuserlimitloginpreblockduration'
+export { UploadDevicePublicKeyAction } from './uploaddevicepublickey'
+export { SendKeyRequestAction } from './sendkeyrequest'
diff --git a/src/action/removeu2fkey.ts b/src/action/removeu2fkey.ts
new file mode 100644
index 0000000..5fa2ad5
--- /dev/null
+++ b/src/action/removeu2fkey.ts
@@ -0,0 +1,52 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { ParentAction } from './basetypes'
+import { throwOutOfRange } from './meta/util'
+
+const actionType = 'RemoveParentU2FKey'
+
+export class RemoveParentU2fKeyAction extends ParentAction {
+ readonly keyHandle: Buffer
+ readonly publicKey: Buffer
+
+ constructor ({ keyHandle, publicKey }: {
+ keyHandle: Buffer
+ publicKey: Buffer
+ }) {
+ super()
+
+ if (keyHandle.length > 2048) throwOutOfRange({ actionType, field: 'keyHandle', value: keyHandle.length })
+ if (publicKey.length > 2048) throwOutOfRange({ actionType, field: 'publicKey', value: publicKey.length })
+
+ this.keyHandle = keyHandle
+ this.publicKey = publicKey
+ }
+
+ static parse = ({ keyHandle, publicKey }: SerializedRemoveParentU2fKeyAction) => (
+ new RemoveParentU2fKeyAction({
+ keyHandle: Buffer.from(keyHandle, 'base64'),
+ publicKey: Buffer.from(publicKey, 'base64')
+ })
+ )
+}
+
+export interface SerializedRemoveParentU2fKeyAction {
+ type: 'REMOVE_PARENT_U2F'
+ keyHandle: string
+ publicKey: string
+}
diff --git a/src/action/replytokeyrequest.ts b/src/action/replytokeyrequest.ts
new file mode 100644
index 0000000..74cdd4d
--- /dev/null
+++ b/src/action/replytokeyrequest.ts
@@ -0,0 +1,74 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { AppLogicAction } from './basetypes'
+import { InvalidActionParameterException } from './meta/exception'
+import { assertSafeInteger } from './meta/util'
+
+const actionType = 'ReplyToKeyRequestAction'
+
+export class ReplyToKeyRequestAction extends AppLogicAction {
+ readonly requestServerSequenceNumber: number
+ readonly tempKey: Buffer
+ readonly encryptedKey: Buffer
+ readonly signature: Buffer
+
+ constructor ({
+ requestServerSequenceNumber,
+ tempKey,
+ encryptedKey,
+ signature
+ }: {
+ requestServerSequenceNumber: number
+ tempKey: Buffer
+ encryptedKey: Buffer
+ signature: Buffer
+ }) {
+ super()
+
+ assertSafeInteger({ value: requestServerSequenceNumber, field: 'requestServerSequenceNumber', actionType })
+
+ if (tempKey.length !== 32 || encryptedKey.length !== 16 || signature.length !== 64) {
+ throw new InvalidActionParameterException({
+ actionType,
+ staticMessage: 'key/signature has wrong length'
+ })
+ }
+
+ this.requestServerSequenceNumber = requestServerSequenceNumber
+ this.tempKey = tempKey
+ this.encryptedKey = encryptedKey
+ this.signature = signature
+ }
+
+ static parse = ({ rsn, tempKey, encryptedKey, signature }: SerializedReplyToKeyRequestAction) => (
+ new ReplyToKeyRequestAction({
+ requestServerSequenceNumber: rsn,
+ tempKey: Buffer.from(tempKey, 'base64'),
+ encryptedKey: Buffer.from(encryptedKey, 'base64'),
+ signature: Buffer.from(signature, 'base64')
+ })
+ )
+}
+
+export interface SerializedReplyToKeyRequestAction {
+ type: 'REPLY_TO_KEY_REQUEST'
+ rsn: number
+ tempKey: string
+ encryptedKey: string
+ signature: string
+}
diff --git a/src/action/resetparentblockedtimes.ts b/src/action/reportu2flogin.ts
similarity index 52%
rename from src/action/resetparentblockedtimes.ts
rename to src/action/reportu2flogin.ts
index 690095c..9d16f9a 100644
--- a/src/action/resetparentblockedtimes.ts
+++ b/src/action/reportu2flogin.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,31 +16,15 @@
*/
import { ParentAction } from './basetypes'
-import { assertIdWithinFamily } from './meta/util'
-const actionType = 'ResetParentBlockedTimesAction'
+export class ReportU2fLoginAction extends ParentAction {
+ static instance = new ReportU2fLoginAction()
-export class ResetParentBlockedTimesAction extends ParentAction {
- readonly parentId: string
-
- constructor ({ parentId }: {
- parentId: string
- }) {
+ private constructor () {
super()
-
- assertIdWithinFamily({ actionType, field: 'parentId', value: parentId })
-
- this.parentId = parentId
}
-
- static parse = ({ parentId }: SerializedResetParentBlockedTimesAction) => (
- new ResetParentBlockedTimesAction({
- parentId
- })
- )
}
-export interface SerializedResetParentBlockedTimesAction {
- type: 'RESET_PARENT_BLOCKED_TIMES'
- parentId: string
+export interface SerializedReportU2fLoginAction {
+ type: 'REPORT_U2F_LOGIN'
}
diff --git a/src/action/reviewchildtaskaction.ts b/src/action/reviewchildtaskaction.ts
index fc61d39..2389505 100644
--- a/src/action/reviewchildtaskaction.ts
+++ b/src/action/reviewchildtaskaction.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -24,11 +24,13 @@ export class ReviewChildTaskAction extends ParentAction {
readonly taskId: string
readonly ok: boolean
readonly time: number
+ readonly day?: number
- constructor ({ taskId, ok, time }: {
+ constructor ({ taskId, ok, time, day }: {
taskId: string
ok: boolean
time: number
+ day?: number
}) {
super()
@@ -39,13 +41,22 @@ export class ReviewChildTaskAction extends ParentAction {
throwOutOfRange({ actionType, field: 'time', value: time })
}
+ if (day !== undefined) {
+ assertSafeInteger({ actionType, field: 'day', value: day })
+
+ if (day < 0) {
+ throwOutOfRange({ actionType, field: 'day', value: day })
+ }
+ }
+
this.taskId = taskId
this.ok = ok
this.time = time
+ this.day = day
}
- static parse = ({ taskId, ok, time }: SerializedReviewChildTaskAction) => (
- new ReviewChildTaskAction({ taskId, ok, time })
+ static parse = ({ taskId, ok, time, day }: SerializedReviewChildTaskAction) => (
+ new ReviewChildTaskAction({ taskId, ok, time, day })
)
}
@@ -54,4 +65,5 @@ export interface SerializedReviewChildTaskAction {
taskId: string
ok: boolean
time: number
+ day?: number
}
diff --git a/src/action/sendkeyrequest.ts b/src/action/sendkeyrequest.ts
new file mode 100644
index 0000000..a4bbbec
--- /dev/null
+++ b/src/action/sendkeyrequest.ts
@@ -0,0 +1,110 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { AppLogicAction } from './basetypes'
+import { InvalidActionParameterException } from './meta/exception'
+import { assertIdWithinFamily, assertSafeInteger } from './meta/util'
+import { types } from '../database/keyrequest'
+
+const actionType = 'SendKeyRequestAction'
+
+export class SendKeyRequestAction extends AppLogicAction {
+ readonly deviceSequenceNumber: number
+ readonly deviceId?: string
+ readonly categoryId?: string
+ readonly type: number
+ readonly tempKey: Buffer
+ readonly signature: Buffer
+
+ constructor ({
+ deviceSequenceNumber,
+ deviceId,
+ categoryId,
+ type,
+ tempKey,
+ signature
+ }: {
+ deviceSequenceNumber: number
+ deviceId?: string
+ categoryId?: string
+ type: number
+ tempKey: Buffer
+ signature: Buffer
+ }) {
+ super()
+
+ assertSafeInteger({ value: deviceSequenceNumber, field: 'deviceSequenceNumber', actionType })
+ assertSafeInteger({ value: type, field: 'deviceSequenceNumber', actionType })
+
+ if (tempKey.length != 32 || signature.length != 64) {
+ throw new InvalidActionParameterException({
+ actionType,
+ staticMessage: 'key/signature has wrong length'
+ })
+ }
+
+ if (deviceId !== undefined) {
+ assertIdWithinFamily({ value: deviceId, actionType, field: 'deviceId' })
+ }
+
+ if (categoryId !== undefined) {
+ assertIdWithinFamily({ value: categoryId, actionType, field: 'categoryId' })
+ }
+
+ if (deviceId !== undefined && categoryId !== undefined) {
+ throw new InvalidActionParameterException({
+ actionType,
+ staticMessage: 'can not specify device and category at the same time'
+ })
+ }
+
+ if (types.all.indexOf(type) === -1) {
+ throw new InvalidActionParameterException({
+ actionType,
+ staticMessage: 'invalid type'
+ })
+ }
+
+ this.deviceSequenceNumber = deviceSequenceNumber
+ this.deviceId = deviceId
+ this.categoryId = categoryId
+ this.type = type
+ this.tempKey = tempKey
+ this.signature = signature
+ }
+
+ static parse = ({ dsn, deviceId, categoryId, dataType, tempKey, signature }: SerializedSendKeyRequestAction) => (
+ new SendKeyRequestAction({
+ deviceSequenceNumber: dsn,
+ deviceId,
+ categoryId,
+ type: dataType,
+ tempKey: Buffer.from(tempKey, 'base64'),
+ signature: Buffer.from(signature, 'base64')
+ })
+ )
+}
+
+export interface SerializedSendKeyRequestAction {
+ type: 'SEND_KEY_REQUEST'
+ dsn: number
+ deviceId?: string
+ categoryId?: string
+ dataType: number
+ tempKey: string
+ signature: string
+}
diff --git a/src/action/serialization/applogicaction.ts b/src/action/serialization/applogicaction.ts
index cef77f1..2aabcef 100644
--- a/src/action/serialization/applogicaction.ts
+++ b/src/action/serialization/applogicaction.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -19,26 +19,36 @@ import { AddInstalledAppsAction, SerializedAddInstalledAppsAction } from '../add
import { AddUsedTimeAction, SerializedAddUsedTimeAction } from '../addusedtime'
import { AddUsedTimeActionVersion2, SerializedAddUsedTimeActionVersion2 } from '../addusedtime2'
import { AppLogicAction } from '../basetypes'
+import { FinishKeyRequestAction, SerializedFinishKeyRequestAction } from '../finishkeyrequest'
import { ForceSyncAction, SerializedForceSyncAction } from '../forcesync'
+import { ReplyToKeyRequestAction, SerializedReplyToKeyRequestAction } from '../replytokeyrequest'
import { MarkTaskPendingAction, SerializedMarkTaskPendingAction } from '../marktaskpendingaction'
import { UnknownActionTypeException } from '../meta/exception'
+import { UpdateInstalledAppsAction, SerializedUpdateInstalledAppsAction } from '../updateinstalledapps'
import { RemoveInstalledAppsAction, SerializedRemoveInstalledAppsAction } from '../removeinstalledapps'
+import { SendKeyRequestAction, SerializedSendKeyRequestAction } from '../sendkeyrequest'
import { SerializedSignOutAtDeviceAction, SignOutAtDeviceAction } from '../signoutatdevice'
import { SerialiezdTriedDisablingDeviceAdminAction, TriedDisablingDeviceAdminAction } from '../trieddisablingdeviceadmin'
import { SerializedUpdateAppActivitiesAction, UpdateAppActivitiesAction } from '../updateappactivities'
import { SerializedUpdateDeviceStatusAction, UpdateDeviceStatusAction } from '../updatedevicestatus'
+import { SerializedUploadDevicePublicKeyAction, UploadDevicePublicKeyAction } from '../uploaddevicepublickey'
export type SerializedAppLogicAction =
SerializedAddInstalledAppsAction |
SerializedAddUsedTimeAction |
SerializedAddUsedTimeActionVersion2 |
+ SerializedFinishKeyRequestAction |
SerializedForceSyncAction |
+ SerializedReplyToKeyRequestAction |
SerializedMarkTaskPendingAction |
+ SerializedUpdateInstalledAppsAction |
SerializedRemoveInstalledAppsAction |
+ SerializedSendKeyRequestAction |
SerializedSignOutAtDeviceAction |
SerialiezdTriedDisablingDeviceAdminAction |
SerializedUpdateAppActivitiesAction |
- SerializedUpdateDeviceStatusAction
+ SerializedUpdateDeviceStatusAction |
+ SerializedUploadDevicePublicKeyAction
export const parseAppLogicAction = (serialized: SerializedAppLogicAction): AppLogicAction => {
if (serialized.type === 'ADD_USED_TIME') {
@@ -47,20 +57,30 @@ export const parseAppLogicAction = (serialized: SerializedAppLogicAction): AppLo
return AddUsedTimeActionVersion2.parse(serialized)
} else if (serialized.type === 'ADD_INSTALLED_APPS') {
return AddInstalledAppsAction.parse(serialized)
+ } else if (serialized.type === 'FINISH_KEY_REQUEST') {
+ return FinishKeyRequestAction.parse(serialized)
} else if (serialized.type === 'FORCE_SYNC') {
- return ForceSyncAction.parse(serialized)
+ return ForceSyncAction.instance
+ } else if (serialized.type === 'REPLY_TO_KEY_REQUEST') {
+ return ReplyToKeyRequestAction.parse(serialized)
} else if (serialized.type === 'MARK_TASK_PENDING') {
return MarkTaskPendingAction.parse(serialized)
+ } else if (serialized.type === 'UPDATE_INSTALLED_APPS') {
+ return UpdateInstalledAppsAction.parse(serialized)
} else if (serialized.type === 'REMOVE_INSTALLED_APPS') {
return RemoveInstalledAppsAction.parse(serialized)
+ } else if (serialized.type === 'SEND_KEY_REQUEST') {
+ return SendKeyRequestAction.parse(serialized)
} else if (serialized.type === 'SIGN_OUT_AT_DEVICE') {
- return SignOutAtDeviceAction.parse(serialized)
+ return SignOutAtDeviceAction.instance
} else if (serialized.type === 'TRIED_DISABLING_DEVICE_ADMIN') {
return new TriedDisablingDeviceAdminAction()
} else if (serialized.type === 'UPDATE_APP_ACTIVITIES') {
return UpdateAppActivitiesAction.parse(serialized)
} else if (serialized.type === 'UPDATE_DEVICE_STATUS') {
return UpdateDeviceStatusAction.parse(serialized)
+ } else if (serialized.type === 'UPLOAD_DEVICE_PUBLIC_KEY') {
+ return UploadDevicePublicKeyAction.parse(serialized)
} else {
throw new UnknownActionTypeException({ group: 'app logic' })
}
diff --git a/src/action/serialization/childaction.ts b/src/action/serialization/childaction.ts
index 231fb3c..d733355 100644
--- a/src/action/serialization/childaction.ts
+++ b/src/action/serialization/childaction.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -25,7 +25,7 @@ export const parseChildAction = (serialized: SerializedChildAction) => {
if (serialized.type === 'CHILD_CHANGE_PASSWORD') {
return ChildChangePasswordAction.parse(serialized)
} else if (serialized.type === 'CHILD_SIGN_IN') {
- return ChildSignInAction.parse(serialized)
+ return ChildSignInAction.instance
} else {
throw new UnknownActionTypeException({ group: 'child' })
}
diff --git a/src/action/serialization/parentaction.ts b/src/action/serialization/parentaction.ts
index b5ff43e..199d603 100644
--- a/src/action/serialization/parentaction.ts
+++ b/src/action/serialization/parentaction.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -17,6 +17,7 @@
import { AddCategoryAppsAction, SerializedAddCategoryAppsAction } from '../addcategoryapps'
import { AddCategoryNetworkIdAction, SerializedAddCategoryNetworkIdAction } from '../addcategorynetworkid'
+import { AddParentU2fKeyAction, SerializedAddParentU2fKeyAction } from '../addu2fkey'
import { AddUserAction, SerializedAddUserAction } from '../adduser'
import { ParentAction } from '../basetypes'
import { ChangeParentPasswordAction, SerializedChangeParentPasswordAction } from '../changeparentpassword'
@@ -27,12 +28,13 @@ import { DeleteChildTaskAction, SerializedDeleteChildTaskAction } from '../delet
import { DeleteTimeLimitRuleAction, SerializedDeleteTimeLimitRuleAction } from '../deletetimelimitrule'
import { IgnoreManipulationAction, SerializedIgnoreManipulationAction } from '../ignoremanipulation'
import { IncrementCategoryExtraTimeAction, SerializedIncrementCategoryExtraTimeAction } from '../incrementcategoryextratime'
+import { ReportU2fLoginAction, SerializedReportU2fLoginAction } from '../reportu2flogin'
import { UnknownActionTypeException } from '../meta/exception'
import { RemoveCategoryAppsAction, SerializedRemoveCategoryAppsAction } from '../removecategoryapps'
+import { RemoveParentU2fKeyAction, SerializedRemoveParentU2fKeyAction } from '../removeu2fkey'
import { RemoveUserAction, SerializedRemoveUserAction } from '../removeuser'
import { RenameChildAction, SerializedRenameChildAction } from '../renamechild'
import { ResetCategoryNetworkIdsAction, SerializeResetCategoryNetworkIdsAction } from '../resetcategorynetworkids'
-import { ResetParentBlockedTimesAction, SerializedResetParentBlockedTimesAction } from '../resetparentblockedtimes'
import { ReviewChildTaskAction, SerializedReviewChildTaskAction } from '../reviewchildtaskaction'
import { SerializedSetCategoryExtraTimeAction, SetCategoryExtraTimeAction } from '../setcategoryextratime'
import { SerializedSetCategoryForUnassignedAppsAction, SetCategoryForUnassignedAppsAction } from '../setcategoryforunassignedapps'
@@ -51,6 +53,7 @@ import { SerializedUpdateCategoryBatteryLimitAction, UpdateCategoryBatteryLimitA
import { SerializedUpdateCategoryBlockAllNotificationsAction, UpdateCategoryBlockAllNotificationsAction } from '../updatecategoryblockallnotifications'
import { SerializedUpdateCategoryBlockedTimesAction, UpdateCategoryBlockedTimesAction } from '../updatecategoryblockedtimes'
import { SerializedUpdatCategoryDisableLimitsAction, UpdateCategoryDisableLimitsAction } from '../updatecategorydisablelimits'
+import { SerializedUpdateCategoryFlagsAction, UpdateCategoryFlagsAction } from '../updatecategoryflags'
import { SerializedUpdateCategorySortingAction, UpdateCategorySortingAction } from '../updatecategorysorting'
import { SerializedUpdateCategoryTemporarilyBlockedAction, UpdateCategoryTemporarilyBlockedAction } from '../updatecategorytemporarilyblocked'
import { SerializedUpdateCategoryTimeWarningsAction, UpdateCategoryTimeWarningsAction } from '../updatecategorytimewarnings'
@@ -59,15 +62,16 @@ import { SerializedUpdateChildTaskAction, UpdateChildTaskAction } from '../updat
import { SerializedUpdateDeviceNameAction, UpdateDeviceNameAction } from '../updatedevicename'
import { SerializedUpdateEnableActivityLevelBlockingAction, UpdateEnableActivityLevelBlockingAction } from '../updateenableactivitylevelblocking'
import { SerialiizedUpdateNetworkTimeVerificationAction, UpdateNetworkTimeVerificationAction } from '../updatenetworktimeverification'
-import { SerializedUpdateParentBlockedTimesAction, UpdateParentBlockedTimesAction } from '../updateparentblockedtimes'
import { SerializedUpdateParentNotificationFlagsAction, UpdateParentNotificationFlagsAction } from '../updateparentnotificationflags'
import { SerializedUpdateTimelimitRuleAction, UpdateTimelimitRuleAction } from '../updatetimelimitrule'
import { SerializedUpdateUserFlagsAction, UpdateUserFlagsAction } from '../updateuserflags'
import { SerializedUpdateUserLimitLoginCategory, UpdateUserLimitLoginCategory } from '../updateuserlimitlogincategory'
+import { SerializedUpdateUserLimitLoginPreBlockDuration, UpdateUserLimitLoginPreBlockDuration } from '../updateuserlimitloginpreblockduration'
export type SerializedParentAction =
SerializedAddCategoryAppsAction |
SerializedAddCategoryNetworkIdAction |
+ SerializedAddParentU2fKeyAction |
SerializedAddUserAction |
SerializedChangeParentPasswordAction |
SerializedCreateCategoryAction |
@@ -77,11 +81,12 @@ export type SerializedParentAction =
SerializedDeleteTimeLimitRuleAction |
SerializedIgnoreManipulationAction |
SerializedIncrementCategoryExtraTimeAction |
+ SerializedReportU2fLoginAction |
SerializedRemoveCategoryAppsAction |
+ SerializedRemoveParentU2fKeyAction |
SerializedRemoveUserAction |
SerializedRenameChildAction |
SerializeResetCategoryNetworkIdsAction |
- SerializedResetParentBlockedTimesAction |
SerializedReviewChildTaskAction |
SerializedSetCategoryForUnassignedAppsAction |
SerializedSetChildPasswordAction |
@@ -100,6 +105,7 @@ export type SerializedParentAction =
SerializedUpdateCategoryBlockAllNotificationsAction |
SerializedUpdateCategoryBlockedTimesAction |
SerializedUpdatCategoryDisableLimitsAction |
+ SerializedUpdateCategoryFlagsAction |
SerializedUpdateCategorySortingAction |
SerializedUpdateCategoryTemporarilyBlockedAction |
SerializedUpdateCategoryTimeWarningsAction |
@@ -108,17 +114,19 @@ export type SerializedParentAction =
SerializedUpdateDeviceNameAction |
SerializedUpdateEnableActivityLevelBlockingAction |
SerialiizedUpdateNetworkTimeVerificationAction |
- SerializedUpdateParentBlockedTimesAction |
SerializedUpdateParentNotificationFlagsAction |
SerializedUpdateTimelimitRuleAction |
SerializedUpdateUserFlagsAction |
- SerializedUpdateUserLimitLoginCategory
+ SerializedUpdateUserLimitLoginCategory |
+ SerializedUpdateUserLimitLoginPreBlockDuration
export const parseParentAction = (action: SerializedParentAction): ParentAction => {
if (action.type === 'ADD_CATEGORY_APPS') {
return AddCategoryAppsAction.parse(action)
} else if (action.type === 'ADD_CATEGORY_NETWORK_ID') {
return AddCategoryNetworkIdAction.parse(action)
+ } else if (action.type === 'ADD_PARENT_U2F') {
+ return AddParentU2fKeyAction.parse(action)
} else if (action.type === 'ADD_USER') {
return AddUserAction.parse(action)
} else if (action.type === 'CHANGE_PARENT_PASSWORD') {
@@ -137,16 +145,18 @@ export const parseParentAction = (action: SerializedParentAction): ParentAction
return IgnoreManipulationAction.parse(action)
} else if (action.type === 'INCREMENT_CATEGORY_EXTRATIME') {
return IncrementCategoryExtraTimeAction.parse(action)
+ } else if (action.type === 'REPORT_U2F_LOGIN') {
+ return ReportU2fLoginAction.instance
} else if (action.type === 'REMOVE_CATEGORY_APPS') {
return RemoveCategoryAppsAction.parse(action)
+ } else if (action.type === 'REMOVE_PARENT_U2F') {
+ return RemoveParentU2fKeyAction.parse(action)
} else if (action.type === 'REMOVE_USER') {
return RemoveUserAction.parse(action)
} else if (action.type === 'RENAME_CHILD') {
return RenameChildAction.parse(action)
} else if (action.type === 'RESET_CATEGORY_NETWORK_IDS') {
return ResetCategoryNetworkIdsAction.parse(action)
- } else if (action.type === 'RESET_PARENT_BLOCKED_TIMES') {
- return ResetParentBlockedTimesAction.parse(action)
} else if (action.type === 'REVIEW_CHILD_TASK') {
return ReviewChildTaskAction.parse(action)
} else if (action.type === 'SET_CATEGORY_EXTRA_TIME') {
@@ -183,6 +193,8 @@ export const parseParentAction = (action: SerializedParentAction): ParentAction
return UpdateCategoryBlockedTimesAction.parse(action)
} else if (action.type === 'UPDATE_CATEGORY_DISABLE_LIMITS') {
return UpdateCategoryDisableLimitsAction.parse(action)
+ } else if (action.type === 'UPDATE_CATEGORY_FLAGS') {
+ return UpdateCategoryFlagsAction.parse(action)
} else if (action.type === 'UPDATE_CATEGORY_SORTING') {
return UpdateCategorySortingAction.parse(action)
} else if (action.type === 'UPDATE_CATEGORY_TIME_WARNINGS') {
@@ -199,8 +211,6 @@ export const parseParentAction = (action: SerializedParentAction): ParentAction
return UpdateEnableActivityLevelBlockingAction.parse(action)
} else if (action.type === 'UPDATE_NETWORK_TIME_VERIFICATION') {
return UpdateNetworkTimeVerificationAction.parse(action)
- } else if (action.type === 'UPDATE_PARENT_BLOCKED_TIMES') {
- return UpdateParentBlockedTimesAction.parse(action)
} else if (action.type === 'UPDATE_PARENT_NOTIFICATION_FLAGS') {
return UpdateParentNotificationFlagsAction.parse(action)
} else if (action.type === 'UPDATE_TIMELIMIT_RULE') {
@@ -209,6 +219,8 @@ export const parseParentAction = (action: SerializedParentAction): ParentAction
return UpdateUserFlagsAction.parse(action)
} else if (action.type === 'UPDATE_USER_LIMIT_LOGIN_CATEGORY') {
return UpdateUserLimitLoginCategory.parse(action)
+ } else if (action.type === 'UPDATE_USER_LIMIT_LOGIN_PRE_BLOCK_DURATION') {
+ return UpdateUserLimitLoginPreBlockDuration.parse(action)
} else {
throw new UnknownActionTypeException({ group: 'parent' })
}
diff --git a/src/action/setchildpassword.ts b/src/action/setchildpassword.ts
index 34fcb8b..7dc7b4e 100644
--- a/src/action/setchildpassword.ts
+++ b/src/action/setchildpassword.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-import { assertParentPasswordValid, ParentPassword, ParentPasswordValidationException } from '../api/schema'
+import { assertParentPasswordValid, EncryptableParentPassword, ParentPasswordValidationException } from '../api/schema'
import { ParentAction } from './basetypes'
import { InvalidActionParameterException } from './meta/exception'
import { assertIdWithinFamily } from './meta/util'
@@ -24,11 +24,11 @@ const actionType = 'SetChildPasswordAction'
export class SetChildPasswordAction extends ParentAction {
readonly childUserId: string
- readonly newPassword: ParentPassword
+ readonly newPassword: EncryptableParentPassword
constructor ({ childUserId, newPassword }: {
childUserId: string
- newPassword: ParentPassword
+ newPassword: EncryptableParentPassword
}) {
super()
@@ -60,5 +60,5 @@ export class SetChildPasswordAction extends ParentAction {
export interface SerializedSetChildPasswordAction {
type: 'SET_CHILD_PASSWORD'
childId: string
- newPassword: ParentPassword
+ newPassword: EncryptableParentPassword
}
diff --git a/src/action/signoutatdevice.ts b/src/action/signoutatdevice.ts
index 773cdbd..1799ce4 100644
--- a/src/action/signoutatdevice.ts
+++ b/src/action/signoutatdevice.ts
@@ -23,8 +23,6 @@ export class SignOutAtDeviceAction extends AppLogicAction {
private constructor () {
super()
}
-
- static parse = (_: SerializedSignOutAtDeviceAction) => SignOutAtDeviceAction.instance
}
export interface SerializedSignOutAtDeviceAction {
diff --git a/src/action/updatecategoryblockallnotifications.ts b/src/action/updatecategoryblockallnotifications.ts
index 40924e5..da59934 100644
--- a/src/action/updatecategoryblockallnotifications.ts
+++ b/src/action/updatecategoryblockallnotifications.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,25 +16,43 @@
*/
import { ParentAction } from './basetypes'
-import { assertIdWithinFamily } from './meta/util'
+import { assertIdWithinFamily, assertSafeInteger, throwOutOfRange } from './meta/util'
const actionType = 'UpdateCategoryBlockAllNotificationsAction'
export class UpdateCategoryBlockAllNotificationsAction extends ParentAction {
readonly categoryId: string
readonly blocked: boolean
+ readonly blockDelay: number | undefined
- constructor ({ categoryId, blocked }: {categoryId: string, blocked: boolean}) {
+ constructor ({ categoryId, blocked, blockDelay }: {
+ categoryId: string
+ blocked: boolean
+ blockDelay: number | undefined
+ }) {
super()
assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
+ if (blockDelay !== undefined) {
+ assertSafeInteger({ actionType, field: 'blockDelay', value: blockDelay })
+
+ if (blockDelay < 0) {
+ throwOutOfRange({ actionType, field: 'blockDelay', value: blockDelay })
+ }
+ }
+
this.categoryId = categoryId
this.blocked = blocked
+ this.blockDelay = blockDelay
}
- static parse = ({ categoryId, blocked }: SerializedUpdateCategoryBlockAllNotificationsAction) => (
- new UpdateCategoryBlockAllNotificationsAction({ categoryId, blocked })
+ static parse = ({ categoryId, blocked, blockDelay }: SerializedUpdateCategoryBlockAllNotificationsAction) => (
+ new UpdateCategoryBlockAllNotificationsAction({
+ categoryId,
+ blocked,
+ blockDelay: blockDelay
+ })
)
}
@@ -42,4 +60,5 @@ export interface SerializedUpdateCategoryBlockAllNotificationsAction {
type: 'UPDATE_CATEGORY_BLOCK_ALL_NOTIFICATIONS'
categoryId: string
blocked: boolean
+ blockDelay: number | undefined
}
diff --git a/src/action/updatecategoryflags.ts b/src/action/updatecategoryflags.ts
new file mode 100644
index 0000000..b2c05f6
--- /dev/null
+++ b/src/action/updatecategoryflags.ts
@@ -0,0 +1,68 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { maxCategoryFlags } from '../database/category'
+import { ParentAction } from './basetypes'
+import { InvalidActionParameterException } from './meta/exception'
+import { assertIdWithinFamily, assertSafeInteger } from './meta/util'
+
+const actionType = 'UpdateCategoryFlagsAction'
+
+export class UpdateCategoryFlagsAction extends ParentAction {
+ readonly categoryId: string
+ readonly modifiedBits: number
+ readonly newValues: number
+
+ constructor ({ categoryId, modifiedBits, newValues }: {
+ categoryId: string
+ modifiedBits: number
+ newValues: number
+ }) {
+ super()
+
+ assertIdWithinFamily({ actionType, field: 'categoryId', value: categoryId })
+ assertSafeInteger({ actionType, field: 'modifiedBits', value: modifiedBits })
+ assertSafeInteger({ actionType, field: 'newValues', value: newValues })
+
+ if ((modifiedBits | maxCategoryFlags) !== maxCategoryFlags || (modifiedBits | newValues) !== modifiedBits) {
+ throw new InvalidActionParameterException({
+ actionType,
+ staticMessage: 'flags are out of the valid range',
+ dynamicMessage: 'flags are out of the valid range: ' + modifiedBits + ', ' + newValues
+ })
+ }
+
+ this.categoryId = categoryId
+ this.modifiedBits = modifiedBits
+ this.newValues = newValues
+ }
+
+ static parse = ({ categoryId, modified, values }: SerializedUpdateCategoryFlagsAction) => (
+ new UpdateCategoryFlagsAction({
+ categoryId,
+ modifiedBits: modified,
+ newValues: values
+ })
+ )
+}
+
+export interface SerializedUpdateCategoryFlagsAction {
+ type: 'UPDATE_CATEGORY_FLAGS'
+ categoryId: string
+ modified: number
+ values: number
+}
diff --git a/src/action/updatecategorytimewarnings.ts b/src/action/updatecategorytimewarnings.ts
index d69583e..19abc09 100644
--- a/src/action/updatecategorytimewarnings.ts
+++ b/src/action/updatecategorytimewarnings.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,6 +16,7 @@
*/
import { allowedTimeWarningFlags } from '../database/category'
+import { categoryTimeWarningConstants } from '../database/categorytimewarning'
import { ParentAction } from './basetypes'
import { assertIdWithinFamily, assertSafeInteger, throwOutOfRange } from './meta/util'
@@ -25,11 +26,13 @@ export class UpdateCategoryTimeWarningsAction extends ParentAction {
readonly categoryId: string
readonly enable: boolean
readonly flags: number
+ readonly minutes?: number
- constructor ({ categoryId, enable, flags }: {
+ constructor ({ categoryId, enable, flags, minutes }: {
categoryId: string
enable: boolean
- flags: number
+ flags: number,
+ minutes?: number
}) {
super()
@@ -40,13 +43,25 @@ export class UpdateCategoryTimeWarningsAction extends ParentAction {
throwOutOfRange({ actionType, field: 'flags', value: flags })
}
+ if (minutes !== undefined) {
+ assertSafeInteger({ actionType, field: 'minutes', value: minutes })
+
+ if (
+ minutes < categoryTimeWarningConstants.minMinutes ||
+ minutes > categoryTimeWarningConstants.maxMinutes
+ ) {
+ throwOutOfRange({ actionType, field: 'minutes', value: minutes })
+ }
+ }
+
this.categoryId = categoryId
this.enable = enable
this.flags = flags
+ this.minutes = minutes
}
- static parse = ({ categoryId, enable, flags }: SerializedUpdateCategoryTimeWarningsAction) => (
- new UpdateCategoryTimeWarningsAction({ categoryId, enable, flags })
+ static parse = ({ categoryId, enable, flags, minutes }: SerializedUpdateCategoryTimeWarningsAction) => (
+ new UpdateCategoryTimeWarningsAction({ categoryId, enable, flags, minutes })
)
}
@@ -55,4 +70,5 @@ export interface SerializedUpdateCategoryTimeWarningsAction {
categoryId: string
enable: boolean
flags: number
+ minutes?: number
}
diff --git a/src/action/updatedevicestatus.ts b/src/action/updatedevicestatus.ts
index 33a0115..d1ffcd8 100644
--- a/src/action/updatedevicestatus.ts
+++ b/src/action/updatedevicestatus.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,6 +15,7 @@
* along with this program. If not, see .
*/
+import { minPlatformLevel, maxPlatformLevel, minPlatformTypeLength, maxPlatformTypeLength } from '../database/device'
import { NewPermissionStatus } from '../model/newpermissionstatus'
import { ProtectionLevel } from '../model/protectionlevel'
import { RuntimePermissionStatus } from '../model/runtimepermissionstatus'
@@ -32,6 +33,9 @@ export class UpdateDeviceStatusAction extends AppLogicAction {
readonly newAppVersion?: number
readonly didReboot: boolean
readonly isQOrLaterNow: boolean
+ readonly addedManipulationFlags: number
+ readonly platformType?: string
+ readonly platformLevel?: number
constructor ({
newProtetionLevel,
@@ -41,7 +45,10 @@ export class UpdateDeviceStatusAction extends AppLogicAction {
newAccessibilityServiceEnabled,
newAppVersion,
didReboot,
- isQOrLaterNow
+ isQOrLaterNow,
+ addedManipulationFlags,
+ platformType,
+ platformLevel
}: {
newProtetionLevel?: ProtectionLevel
newUsageStatsPermissionStatus?: RuntimePermissionStatus
@@ -51,6 +58,9 @@ export class UpdateDeviceStatusAction extends AppLogicAction {
newAppVersion?: number
didReboot: boolean
isQOrLaterNow: boolean
+ addedManipulationFlags: number
+ platformType?: string
+ platformLevel?: number
}) {
super()
@@ -62,6 +72,22 @@ export class UpdateDeviceStatusAction extends AppLogicAction {
}
}
+ assertSafeInteger({ actionType, field: 'addedManipulationFlags', value: addedManipulationFlags })
+
+ if (platformType !== undefined) {
+ if (platformType.length < minPlatformTypeLength || platformType.length > maxPlatformTypeLength) {
+ throwOutOfRange({ actionType, field: 'platformType.length', value: platformType.length })
+ }
+ }
+
+ if (platformLevel !== undefined) {
+ assertSafeInteger({ actionType, field: 'platformLevel', value: platformLevel })
+
+ if (platformLevel < minPlatformLevel || platformLevel > maxPlatformLevel) {
+ throwOutOfRange({ actionType, field: 'platformLevel', value: platformLevel })
+ }
+ }
+
this.newProtetionLevel = newProtetionLevel
this.newUsageStatsPermissionStatus = newUsageStatsPermissionStatus
this.newNotificationAccessPermission = newNotificationAccessPermission
@@ -70,9 +96,24 @@ export class UpdateDeviceStatusAction extends AppLogicAction {
this.newAppVersion = newAppVersion
this.didReboot = didReboot
this.isQOrLaterNow = isQOrLaterNow
+ this.addedManipulationFlags = addedManipulationFlags
+ this.platformType = platformType
+ this.platformLevel = platformLevel
}
- static parse = ({ protectionLevel, usageStats, notificationAccess, overlayPermission, accessibilityServiceEnabled, appVersion, didReboot, isQOrLaterNow }: SerializedUpdateDeviceStatusAction) => (
+ static parse = ({
+ protectionLevel,
+ usageStats,
+ notificationAccess,
+ overlayPermission,
+ accessibilityServiceEnabled,
+ appVersion,
+ didReboot,
+ isQOrLaterNow,
+ addedManipulationFlags,
+ platformType,
+ platformLevel
+ }: SerializedUpdateDeviceStatusAction) => (
new UpdateDeviceStatusAction({
newProtetionLevel: protectionLevel,
newUsageStatsPermissionStatus: usageStats,
@@ -81,7 +122,10 @@ export class UpdateDeviceStatusAction extends AppLogicAction {
newAccessibilityServiceEnabled: accessibilityServiceEnabled,
newAppVersion: appVersion,
didReboot: !!didReboot,
- isQOrLaterNow: !!isQOrLaterNow
+ isQOrLaterNow: !!isQOrLaterNow,
+ addedManipulationFlags: addedManipulationFlags || 0,
+ platformType: platformType,
+ platformLevel: platformLevel
})
)
}
@@ -96,4 +140,7 @@ export interface SerializedUpdateDeviceStatusAction {
appVersion?: number
didReboot?: boolean
isQOrLaterNow?: boolean
+ addedManipulationFlags?: number
+ platformType?: string
+ platformLevel?: number
}
diff --git a/src/action/updateinstalledapps.ts b/src/action/updateinstalledapps.ts
new file mode 100644
index 0000000..0e664fe
--- /dev/null
+++ b/src/action/updateinstalledapps.ts
@@ -0,0 +1,69 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { AppLogicAction } from './basetypes'
+import { InvalidActionParameterException } from './meta/exception'
+
+const actionType = 'UpdateInstalledAppsAction'
+const SIZE_LIMIT = 1024 * 512
+
+export class UpdateInstalledAppsAction extends AppLogicAction {
+ readonly base?: Buffer
+ readonly diff?: Buffer
+ readonly wipe: boolean
+
+ constructor ({ base, diff, wipe }: {
+ base?: Buffer,
+ diff?: Buffer,
+ wipe: boolean
+ }) {
+ super()
+
+ if (base && base.length > SIZE_LIMIT) {
+ throw new InvalidActionParameterException({
+ actionType,
+ staticMessage: 'base data too big'
+ })
+ }
+
+ if (diff && diff.length > SIZE_LIMIT) {
+ throw new InvalidActionParameterException({
+ actionType,
+ staticMessage: 'diff data too big'
+ })
+ }
+
+ this.base = base
+ this.diff = diff
+ this.wipe = wipe
+ }
+
+ static parse = ({ b, d, w }: SerializedUpdateInstalledAppsAction) => (
+ new UpdateInstalledAppsAction({
+ base: b !== undefined ? Buffer.from(b, 'base64') : undefined,
+ diff: d !== undefined ? Buffer.from(d, 'base64') : undefined,
+ wipe: w
+ })
+ )
+}
+
+export interface SerializedUpdateInstalledAppsAction {
+ type: 'UPDATE_INSTALLED_APPS'
+ b?: string
+ d?: string
+ w: boolean
+}
diff --git a/src/action/updateparentblockedtimes.ts b/src/action/updateparentblockedtimes.ts
deleted file mode 100644
index ff35725..0000000
--- a/src/action/updateparentblockedtimes.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import { BitmapValidationException, validateAndParseBitmask } from '../util/bitmask'
-import { ParentAction } from './basetypes'
-import { InvalidActionParameterException } from './meta/exception'
-import { assertIdWithinFamily } from './meta/util'
-
-const actionType = 'UpdateParentBlockedTimesAction'
-
-export class UpdateParentBlockedTimesAction extends ParentAction {
- readonly parentId: string
- readonly blockedTimes: string
-
- constructor ({ parentId, blockedTimes }: {
- parentId: string
- blockedTimes: string
- }) {
- super()
-
- assertIdWithinFamily({ actionType, field: 'parentId', value: parentId })
-
- try {
- const parsedBlockedTimes = validateAndParseBitmask(blockedTimes, 60 * 24 * 7 /* number of minutes per week */)
-
- for (let day = 0; day < 7; day++) {
- let blockedMinutes = 0
-
- for (let minute = 0; minute < 60 * 24 /* 1 day */; minute++) {
- if (parsedBlockedTimes[day * 60 * 24 + minute]) {
- blockedMinutes++
- }
- }
-
- if (blockedMinutes > 60 * 18 /* 18 hours */) {
- throw new InvalidActionParameterException({
- actionType,
- staticMessage: 'too much blocked minutes per day'
- })
- }
- }
- } catch (ex) {
- if (ex instanceof BitmapValidationException) {
- throw new InvalidActionParameterException({
- actionType,
- staticMessage: 'invalid bitmask'
- })
- } else throw ex
- }
-
- this.parentId = parentId
- this.blockedTimes = blockedTimes
- }
-
- static parse = ({ parentId, times }: SerializedUpdateParentBlockedTimesAction) => (
- new UpdateParentBlockedTimesAction({
- parentId,
- blockedTimes: times
- })
- )
-}
-
-export interface SerializedUpdateParentBlockedTimesAction {
- type: 'UPDATE_PARENT_BLOCKED_TIMES'
- parentId: string
- times: string
-}
diff --git a/src/action/updateparentnotificationflags.ts b/src/action/updateparentnotificationflags.ts
index 329ae05..6285781 100644
--- a/src/action/updateparentnotificationflags.ts
+++ b/src/action/updateparentnotificationflags.ts
@@ -15,6 +15,7 @@
* along with this program. If not, see .
*/
+import { maxMailNotificationFlags } from '../database/user'
import { ParentAction } from './basetypes'
import { assertIdWithinFamily, assertSafeInteger, throwOutOfRange } from './meta/util'
@@ -36,7 +37,7 @@ export class UpdateParentNotificationFlagsAction extends ParentAction {
assertSafeInteger({ actionType, field: 'flags', value: flags })
- if (flags < 0 || flags > 1) {
+ if (flags < 0 || flags > maxMailNotificationFlags) {
throwOutOfRange({ actionType, field: 'flags', value: flags })
}
diff --git a/src/action/updatetimelimitrule.ts b/src/action/updatetimelimitrule.ts
index af8e1ed..6a582f6 100644
--- a/src/action/updatetimelimitrule.ts
+++ b/src/action/updatetimelimitrule.ts
@@ -31,10 +31,12 @@ export class UpdateTimelimitRuleAction extends ParentAction {
readonly end: number
readonly sessionDurationMilliseconds: number
readonly sessionPauseMilliseconds: number
+ readonly perDay: boolean
constructor ({
ruleId, maximumTimeInMillis, dayMask, applyToExtraTimeUsage,
- start, end, sessionDurationMilliseconds, sessionPauseMilliseconds
+ start, end, sessionDurationMilliseconds, sessionPauseMilliseconds,
+ perDay
}: {
ruleId: string
maximumTimeInMillis: number
@@ -44,6 +46,7 @@ export class UpdateTimelimitRuleAction extends ParentAction {
end: number
sessionDurationMilliseconds: number
sessionPauseMilliseconds: number
+ perDay: boolean
}) {
super()
@@ -55,6 +58,7 @@ export class UpdateTimelimitRuleAction extends ParentAction {
this.end = end
this.sessionDurationMilliseconds = sessionDurationMilliseconds
this.sessionPauseMilliseconds = sessionPauseMilliseconds
+ this.perDay = perDay
assertIdWithinFamily({ actionType, field: 'ruleId', value: ruleId })
@@ -90,7 +94,7 @@ export class UpdateTimelimitRuleAction extends ParentAction {
}
}
- static parse = ({ ruleId, time, days, extraTime, start, end, dur, pause }: SerializedUpdateTimelimitRuleAction) => (
+ static parse = ({ ruleId, time, days, extraTime, start, end, dur, pause, perDay }: SerializedUpdateTimelimitRuleAction) => (
new UpdateTimelimitRuleAction({
ruleId,
maximumTimeInMillis: time,
@@ -99,7 +103,8 @@ export class UpdateTimelimitRuleAction extends ParentAction {
start: start ?? MinuteOfDay.MIN,
end: end ?? MinuteOfDay.MAX,
sessionDurationMilliseconds: dur ?? 0,
- sessionPauseMilliseconds: pause ?? 0
+ sessionPauseMilliseconds: pause ?? 0,
+ perDay: perDay ?? false
})
)
}
@@ -114,4 +119,5 @@ export interface SerializedUpdateTimelimitRuleAction {
end?: number
dur?: number
pause?: number
+ perDay?: boolean
}
diff --git a/src/action/updateuserlimitloginpreblockduration.ts b/src/action/updateuserlimitloginpreblockduration.ts
new file mode 100644
index 0000000..10463ea
--- /dev/null
+++ b/src/action/updateuserlimitloginpreblockduration.ts
@@ -0,0 +1,57 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2020 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { maxPreBlockDuration } from '../database/userlimitlogincategory'
+import { ParentAction } from './basetypes'
+import { assertIdWithinFamily, assertSafeInteger, throwOutOfRange } from './meta/util'
+
+const actionType = 'UpdateUserLimitLoginPreBlockDuration'
+
+export class UpdateUserLimitLoginPreBlockDuration extends ParentAction {
+ readonly userId: string
+ readonly preBlockDuration: number
+
+ constructor ({ userId, preBlockDuration }: {
+ userId: string,
+ preBlockDuration: number
+ }) {
+ super()
+
+ assertIdWithinFamily({ actionType, field: 'userId', value: userId })
+ assertSafeInteger({ actionType, field: 'preBlockDuration', value: preBlockDuration })
+
+ if (preBlockDuration < 0 || preBlockDuration > maxPreBlockDuration) {
+ throwOutOfRange({ actionType, field: 'preBlockDuration', value: preBlockDuration })
+ }
+
+ this.userId = userId
+ this.preBlockDuration = preBlockDuration
+ }
+
+ static parse = ({ userId, preBlockDuration }: SerializedUpdateUserLimitLoginPreBlockDuration) => (
+ new UpdateUserLimitLoginPreBlockDuration({
+ userId,
+ preBlockDuration
+ })
+ )
+}
+
+export interface SerializedUpdateUserLimitLoginPreBlockDuration {
+ type: 'UPDATE_USER_LIMIT_LOGIN_PRE_BLOCK_DURATION'
+ userId: string
+ preBlockDuration: number
+}
diff --git a/src/action/uploaddevicepublickey.ts b/src/action/uploaddevicepublickey.ts
new file mode 100644
index 0000000..a136f6e
--- /dev/null
+++ b/src/action/uploaddevicepublickey.ts
@@ -0,0 +1,49 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { AppLogicAction } from './basetypes'
+import { InvalidActionParameterException } from './meta/exception'
+
+const actionType = 'UploadDevicePublicKeyAction'
+
+export class UploadDevicePublicKeyAction extends AppLogicAction {
+ readonly key: Buffer
+
+ constructor ({ key }: { key: Buffer }) {
+ super()
+
+ if (key.length !== 32) {
+ throw new InvalidActionParameterException({
+ actionType,
+ staticMessage: 'key has wrong length'
+ })
+ }
+
+ this.key = key
+ }
+
+ static parse = ({ key }: SerializedUploadDevicePublicKeyAction) => (
+ new UploadDevicePublicKeyAction({
+ key: Buffer.from(key, 'base64')
+ })
+ )
+}
+
+export interface SerializedUploadDevicePublicKeyAction {
+ type: 'UPLOAD_DEVICE_PUBLIC_KEY'
+ key: string
+}
diff --git a/src/api/admin.ts b/src/api/admin.ts
index 5a869ec..22ebf23 100644
--- a/src/api/admin.ts
+++ b/src/api/admin.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -18,11 +18,13 @@
import { json } from 'body-parser'
import { Router } from 'express'
import { BadRequest, Conflict } from 'http-errors'
+import * as Sequelize from 'sequelize'
import { Database } from '../database'
-import { addPurchase } from '../function/purchase'
+import { addPurchase, canDoNextPurchase } from '../function/purchase'
import { getStatusMessage, setStatusMessage } from '../function/statusmessage'
import { EventHandler } from '../monitoring/eventhandler'
import { generatePurchaseId } from '../util/token'
+import { verifyIdentitifyToken, TokenValidationException } from '../util/identity-token'
import { WebsocketApi } from '../websocket'
export const createAdminRouter = ({ database, websocket, eventHandler }: {
@@ -120,7 +122,8 @@ export const createAdminRouter = ({ database, websocket, eventHandler }: {
database,
familyId: userEntry.familyId,
type,
- transactionId: 'manual-' + type + '-' + generatePurchaseId(),
+ service: 'directpurchase',
+ transactionId: 'legacyunlock-' + type + '-' + generatePurchaseId(),
websocket,
transaction
})
@@ -132,5 +135,149 @@ export const createAdminRouter = ({ database, websocket, eventHandler }: {
}
})
+ router.post('/unlock-premium-v2', json(), async (req, res, next) => {
+ try {
+ if (
+ typeof req.body !== 'object' ||
+ typeof req.body.purchaseToken !== 'string' ||
+ typeof req.body.purchaseId !== 'string'
+ ) {
+ throw new BadRequest()
+ }
+
+ const purchaseToken: string = req.body.purchaseToken
+ const purchaseId: string = req.body.purchaseId
+
+ const tokenContent = await verifyIdentitifyToken(purchaseToken)
+
+ if (tokenContent.purpose !== 'purchase') {
+ res.json({ ok: false, error: 'token invalid', detail: 'wrong purpose' })
+
+ return
+ }
+
+ const response = await database.transaction(async (transaction) => {
+ const userValid = await database.user.count({
+ where: {
+ familyId: tokenContent.familyId,
+ userId: tokenContent.userId,
+ mail: tokenContent.mail,
+ type: 'parent'
+ },
+ transaction
+ })
+
+ if (!userValid) return {
+ ok: false,
+ error: 'token invalid',
+ detail: 'user not found'
+ }
+
+ let mailToReturn: string
+
+ if (tokenContent.mail !== '') mailToReturn = tokenContent.mail
+ else {
+ const userEntryWithMail = await database.user.findOne({
+ where: {
+ familyId: tokenContent.familyId,
+ mail: {
+ [Sequelize.Op.ne]: ''
+ },
+ type: 'parent'
+ },
+ transaction
+ })
+
+ if (!userEntryWithMail) return {
+ ok: false,
+ error: 'illegal state',
+ detail: 'no user with mail found'
+ }
+
+ mailToReturn = userEntryWithMail.mail
+ }
+
+ let wasAlreadyExecuted: boolean
+
+ const oldPurchaseByPurchaseId = await database.purchase.findOne({
+ where: {
+ service: 'directpurchase',
+ transactionId: purchaseId
+ }
+ })
+
+ if (oldPurchaseByPurchaseId === null) wasAlreadyExecuted = false
+ else if (oldPurchaseByPurchaseId.familyId === tokenContent.familyId) wasAlreadyExecuted = true
+ else return {
+ ok: false,
+ error: 'purchase id already used'
+ }
+
+ if (!wasAlreadyExecuted) {
+ const familyEntry = await database.family.findOne({
+ where: {
+ familyId: tokenContent.familyId
+ },
+ transaction
+ })
+
+ if (!familyEntry) return {
+ ok: false,
+ error: 'family not found'
+ }
+
+ const canDoPurchase = canDoNextPurchase({ fullVersionUntil: parseInt(familyEntry.fullVersionUntil) })
+
+ if (!canDoPurchase) {
+ const lastPurchase = await database.purchase.findOne({
+ where: {
+ familyId: tokenContent.familyId
+ },
+ transaction,
+ order: [['loggedAt', 'DESC']],
+ limit: 1
+ })
+
+ return {
+ ok: false,
+ error: 'can not renew now',
+ lastPurchase: lastPurchase ? {
+ service: lastPurchase.service,
+ transactionId: lastPurchase.transactionId,
+ timestamp: parseInt(lastPurchase.loggedAt),
+ timestring: new Date(parseInt(lastPurchase.loggedAt)).toISOString()
+ } : undefined
+ }
+ }
+
+ await addPurchase({
+ database,
+ familyId: tokenContent.familyId,
+ type: 'year',
+ service: 'directpurchase',
+ transactionId: purchaseId,
+ websocket,
+ transaction
+ })
+ }
+
+ return {
+ ok: true,
+ mail: mailToReturn,
+ wasAlreadyExecuted
+ }
+ })
+
+ res.json(response)
+ } catch (ex) {
+ if (ex instanceof TokenValidationException) res.json({
+ ok: false,
+ error: 'token invalid',
+ detail: ex.message
+ })
+ else next(ex)
+ }
+ })
+
return router
}
diff --git a/src/api/auth.ts b/src/api/auth.ts
index 985c598..ae13b7e 100644
--- a/src/api/auth.ts
+++ b/src/api/auth.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -48,6 +48,7 @@ export const createAuthRouter = (database: Database) => {
} else {
const { mailLoginToken } = await sendLoginCode({
mail,
+ deviceAuthToken: req.body.deviceAuthToken,
locale: req.body.locale,
database
})
diff --git a/src/api/child.ts b/src/api/child.ts
index f14ad7a..2e298b2 100644
--- a/src/api/child.ts
+++ b/src/api/child.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -24,10 +24,12 @@ import { logoutAtPrimaryDevice } from '../function/child/logout-at-primary-devic
import { setPrimaryDevice } from '../function/child/set-primary-device'
import { WebsocketApi } from '../websocket'
import { isRegisterChildDeviceRequest, isRequestWithAuthToken, isUpdatePrimaryDeviceRequest } from './validator'
+import { EventHandler } from '../monitoring/eventhandler'
-export const createChildRouter = ({ database, websocket }: {
- database: Database,
+export const createChildRouter = ({ database, websocket, eventHandler }: {
+ database: Database
websocket: WebsocketApi
+ eventHandler: EventHandler
}) => {
const router = Router()
@@ -37,15 +39,17 @@ export const createChildRouter = ({ database, websocket }: {
throw new BadRequest()
}
- const { deviceAuthToken, deviceId } = await addChildDevice({
+ const { deviceAuthToken, deviceId, data } = await addChildDevice({
request: req.body,
database,
+ eventHandler,
websocket
})
res.json({
deviceAuthToken,
- ownDeviceId: deviceId
+ ownDeviceId: deviceId,
+ data
})
} catch (ex) {
next(ex)
diff --git a/src/api/index.ts b/src/api/index.ts
index 81910d9..86f7c9e 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -47,8 +47,8 @@ export const createApi = ({ database, websocket, connectedDevicesManager, eventH
})
app.use('/auth', createAuthRouter(database))
- app.use('/child', createChildRouter({ database, websocket }))
- app.use('/parent', createParentRouter({ database, websocket }))
+ app.use('/child', createChildRouter({ database, websocket, eventHandler }))
+ app.use('/parent', createParentRouter({ database, websocket, eventHandler }))
app.use('/purchase', createPurchaseRouter({ database, websocket }))
app.use('/sync', createSyncRouter({ database, websocket, connectedDevicesManager, eventHandler }))
diff --git a/src/api/parent.ts b/src/api/parent.ts
index e9c0030..e0e7eca 100644
--- a/src/api/parent.ts
+++ b/src/api/parent.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,27 +16,38 @@
*/
import { json } from 'body-parser'
+import { createHmac } from 'crypto'
import { Router } from 'express'
import { BadRequest, Forbidden, Unauthorized } from 'http-errors'
import { config } from '../config'
import { Database, Transaction } from '../database'
+import { deleteAccount } from '../function/cleanup/account-deletion'
import { removeDevice } from '../function/device/remove-device'
-import { canRecoverPassword } from '../function/parent/can-recover-password'
import { createAddDeviceToken } from '../function/parent/create-add-device-token'
import { createFamily } from '../function/parent/create-family'
import { getStatusByMailToken } from '../function/parent/get-status-by-mail-address'
import { linkMailAddress } from '../function/parent/link-mail-address'
import { recoverParentPassword } from '../function/parent/recover-parent-password'
import { signInIntoFamily } from '../function/parent/sign-in-into-family'
+import { validateU2fIntegrity, U2fValidationError } from '../function/u2f'
+import { createIdentityToken, MissingSignSecretException } from '../util/identity-token'
import { WebsocketApi } from '../websocket'
+import { EventHandler } from '../monitoring/eventhandler'
import {
- isCanRecoverPasswordRequest, isCreateFamilyByMailTokenRequest,
+ isCreateFamilyByMailTokenRequest,
isCreateRegisterDeviceTokenRequest, isLinkParentMailAddressRequest,
isMailAuthTokenRequestBody, isRecoverParentPasswordRequest,
- isRemoveDeviceRequest, isSignIntoFamilyRequest
+ isRemoveDeviceRequest, isSignIntoFamilyRequest, isRequestIdentityTokenRequest,
+ isDeleteAccountPayload
} from './validator'
-export const createParentRouter = ({ database, websocket }: {database: Database, websocket: WebsocketApi}) => {
+export const createParentRouter = ({
+ database, websocket, eventHandler
+}: {
+ database: Database
+ websocket: WebsocketApi
+ eventHandler: EventHandler
+}) => {
const router = Router()
router.post('/get-status-by-mail-address', json(), async (req, res, next) => {
@@ -73,17 +84,20 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
const result = await createFamily({
database,
+ eventHandler,
firstParentDevice: req.body.parentDevice,
mailAuthToken: req.body.mailAuthToken,
password: req.body.parentPassword,
deviceName: req.body.deviceName,
parentName: req.body.parentName,
- timeZone: req.body.timeZone
+ timeZone: req.body.timeZone,
+ clientLevel: req.body.clientLevel || null
})
res.json({
deviceAuthToken: result.deviceAuthToken,
- ownDeviceId: result.deviceId
+ ownDeviceId: result.deviceId,
+ data: result.data
})
} catch (ex) {
next(ex)
@@ -98,39 +112,24 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
const result = await signInIntoFamily({
database,
+ eventHandler,
newDeviceInfo: req.body.parentDevice,
mailAuthToken: req.body.mailAuthToken,
deviceName: req.body.deviceName,
+ clientLevel: req.body.clientLevel || null,
websocket
})
res.json({
deviceAuthToken: result.deviceAuthToken,
- ownDeviceId: result.deviceId
+ ownDeviceId: result.deviceId,
+ data: result.data
})
} catch (ex) {
next(ex)
}
})
- router.post('/can-recover-password', json(), async (req, res, next) => {
- try {
- if (!isCanRecoverPasswordRequest(req.body)) {
- throw new BadRequest()
- }
-
- const canRecover = await canRecoverPassword({
- database,
- parentUserId: req.body.parentUserId,
- mailAuthToken: req.body.mailAuthToken
- })
-
- res.json({ canRecover })
- } catch (ex) {
- next(ex)
- }
- })
-
router.post('/recover-parent-password', json(), async (req, res, next) => {
try {
if (!isRecoverParentPasswordRequest(req.body)) {
@@ -150,7 +149,7 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
}
})
- async function assertAuthValidAndReturnDeviceEntry ({ deviceAuthToken, parentId, secondPasswordHash, transaction }: {
+ async function assertAuthValidAndReturnDetails ({ deviceAuthToken, parentId, secondPasswordHash, transaction }: {
deviceAuthToken: string
parentId: string
secondPasswordHash: string
@@ -184,6 +183,58 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
if (!parentEntry) {
throw new Unauthorized()
}
+
+ return { deviceEntry, parentEntry }
+ } else if (secondPasswordHash.startsWith('u2f:')) {
+ try {
+ const familyEntryUnsafe = await database.family.findOne({
+ where: {
+ familyId: deviceEntry.familyId
+ },
+ transaction,
+ attributes: ['hasFullVersion']
+ })
+
+ if (!familyEntryUnsafe) {
+ throw new Unauthorized()
+ }
+
+ const familyEntry = { hasFullVersion: familyEntryUnsafe.hasFullVersion }
+
+ const hasFullVersion = familyEntry.hasFullVersion || config.alwaysPro
+
+ const u2fResult = await validateU2fIntegrity({
+ integrity: secondPasswordHash,
+ hasFullVersion,
+ familyId: deviceEntry.familyId,
+ deviceId: deviceEntry.deviceId,
+ database,
+ transaction,
+ calculateHmac: (secret) => createHmac('sha256', secret)
+ .update('direct action')
+ .digest()
+ })
+
+ if (u2fResult.userId !== parentId) throw new Unauthorized()
+
+ const parentEntry = await database.user.findOne({
+ where: {
+ familyId: deviceEntry.familyId,
+ type: 'parent',
+ userId: u2fResult.userId
+ },
+ transaction
+ })
+
+ if (!parentEntry) {
+ throw new Unauthorized()
+ }
+
+ return { deviceEntry, parentEntry }
+ } catch (ex) {
+ if (ex instanceof U2fValidationError) throw new Unauthorized()
+ else throw ex
+ }
} else {
const parentEntry = await database.user.findOne({
where: {
@@ -198,9 +249,9 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
if (!parentEntry) {
throw new Unauthorized()
}
- }
- return deviceEntry
+ return { deviceEntry, parentEntry }
+ }
}
router.post('/create-add-device-token', json(), async (req, res, next) => {
@@ -210,7 +261,7 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
}
const { token, deviceId } = await database.transaction(async (transaction) => {
- const deviceEntry = await assertAuthValidAndReturnDeviceEntry({
+ const { deviceEntry } = await assertAuthValidAndReturnDetails({
deviceAuthToken: req.body.deviceAuthToken,
parentId: req.body.parentId,
secondPasswordHash: req.body.parentPasswordSecondHash,
@@ -254,7 +305,7 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
}
await database.transaction(async (transaction) => {
- const deviceEntry = await assertAuthValidAndReturnDeviceEntry({
+ const { deviceEntry } = await assertAuthValidAndReturnDetails({
deviceAuthToken: req.body.deviceAuthToken,
parentId: req.body.parentUserId,
secondPasswordHash: req.body.parentPasswordSecondHash,
@@ -276,5 +327,50 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
}
})
+ router.post('/create-identity-token', json(), async (req, res, next) => {
+ try {
+ if (!isRequestIdentityTokenRequest(req.body)) {
+ throw new BadRequest()
+ }
+
+ const body = req.body
+
+ await database.transaction(async (transaction) => {
+ const { deviceEntry, parentEntry } = await assertAuthValidAndReturnDetails({
+ deviceAuthToken: body.deviceAuthToken,
+ parentId: body.parentUserId,
+ secondPasswordHash: body.parentPasswordSecondHash,
+ transaction
+ })
+
+ const token = await createIdentityToken({
+ purpose: body.purpose,
+ familyId: deviceEntry.familyId,
+ userId: parentEntry.userId,
+ mail: parentEntry.mail
+ })
+
+ res.json({ token })
+ })
+ } catch (ex) {
+ if (ex instanceof MissingSignSecretException) res.sendStatus(404)
+ else next(ex)
+ }
+ })
+
+ router.post('/delete-account', json(), async (req, res, next) => {
+ try {
+ if (!isDeleteAccountPayload(req.body)) {
+ throw new BadRequest()
+ }
+
+ await deleteAccount({ database, request: req.body, websocket })
+
+ res.sendStatus(200)
+ } catch (ex) {
+ next(ex)
+ }
+ })
+
return router
}
diff --git a/src/api/purchase.ts b/src/api/purchase.ts
index d88e17c..da2ff4d 100644
--- a/src/api/purchase.ts
+++ b/src/api/purchase.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -122,6 +122,7 @@ export const createPurchaseRouter = ({ database, websocket }: {
database,
familyId: deviceEntry.familyId,
type,
+ service: 'googleplay',
transactionId: orderId,
websocket,
transaction
diff --git a/src/api/schema.ts b/src/api/schema.ts
index 27ac31b..afaa5f1 100644
--- a/src/api/schema.ts
+++ b/src/api/schema.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -44,18 +44,33 @@ export interface NewDeviceInfo {
model: string
}
-export interface ParentPassword {
+export interface PlaintextParentPassword {
hash: string
secondHash: string
secondSalt: string
}
-export const assertParentPasswordValid = (password: ParentPassword) => {
+export interface EncryptableParentPassword {
+ hash: string
+ secondHash: string
+ secondSalt: string
+ encrypted?: boolean
+}
+
+export const assertPlaintextParentPasswordValid = (password: PlaintextParentPassword) => {
+ assertParentPasswordValid({ ...password, encrypted: false })
+}
+
+export const assertParentPasswordValid = (password: EncryptableParentPassword) => {
if (password.hash === '' || password.secondHash === '' || password.secondSalt === '') {
throw new ParentPasswordValidationException('missing fields at parent password')
}
- if (!(optionalPasswordRegex.test(password.hash) && optionalPasswordRegex.test(password.secondHash) && optionalSaltRegex.test(password.secondSalt))) {
+ if (!(optionalPasswordRegex.test(password.hash) && optionalSaltRegex.test(password.secondSalt))) {
+ throw new ParentPasswordValidationException('invalid parent password')
+ }
+
+ if (!password.encrypted && !optionalPasswordRegex.test(password.secondHash)) {
throw new ParentPasswordValidationException('invalid parent password')
}
}
@@ -64,33 +79,31 @@ export class ParentPasswordValidationException extends Error {}
export interface CreateFamilyByMailTokenRequest {
mailAuthToken: string
- parentPassword: ParentPassword
+ parentPassword: PlaintextParentPassword
parentDevice: NewDeviceInfo
deviceName: string
timeZone: string
parentName: string
+ clientLevel?: number
}
export interface SignIntoFamilyRequest {
mailAuthToken: string
parentDevice: NewDeviceInfo
deviceName: string
+ clientLevel?: number
}
export interface RecoverParentPasswordRequest {
mailAuthToken: string
- password: ParentPassword
-}
-
-export interface CanRecoverPasswordRequest {
- mailAuthToken: string
- parentUserId: string
+ password: PlaintextParentPassword
}
export interface RegisterChildDeviceRequest {
registerToken: string
childDevice: NewDeviceInfo
deviceName: string
+ clientLevel?: number
}
export interface CreateRegisterDeviceTokenRequest {
@@ -130,6 +143,13 @@ export interface RemoveDeviceRequest {
deviceId: string
}
+export interface RequestIdentityTokenRequest {
+ deviceAuthToken: string
+ parentUserId: string
+ parentPasswordSecondHash: string
+ purpose: 'purchase'
+}
+
export interface RequestWithAuthToken {
deviceAuthToken: string
}
@@ -137,6 +157,7 @@ export interface RequestWithAuthToken {
export interface SendMailLoginCodeRequest {
mail: string
locale: string
+ deviceAuthToken?: string
}
export interface SignInByMailCodeRequest {
@@ -144,5 +165,21 @@ export interface SignInByMailCodeRequest {
receivedCode: string
}
+export interface IdentityTokenCreatePayload {
+ purpose: 'purchase'
+ familyId: string
+ userId: string
+ mail: string
+}
+
+export type IdentityTokenPayload = IdentityTokenCreatePayload & {
+ exp: number
+}
+
+export interface DeleteAccountPayload {
+ deviceAuthToken: string
+ mailAuthTokens: Array
+}
+
export { SerializedParentAction, SerializedChildAction, SerializedAppLogicAction } from '../action/serialization'
export { ServerDataStatus } from '../object/serverdatastatus'
diff --git a/src/api/sync.ts b/src/api/sync.ts
index 88c8755..dd95f9b 100644
--- a/src/api/sync.ts
+++ b/src/api/sync.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -90,7 +90,7 @@ export const createSyncRouter = ({ database, websocket, connectedDevicesManager,
where: {
deviceAuthToken: body.deviceAuthToken
},
- attributes: ['familyId', 'lastConnectivity'],
+ attributes: ['familyId', 'deviceId', 'lastConnectivity'],
transaction
})
@@ -98,7 +98,7 @@ export const createSyncRouter = ({ database, websocket, connectedDevicesManager,
throw new Unauthorized()
}
- const { familyId, lastConnectivity } = deviceEntryUnsafe
+ const { familyId, deviceId, lastConnectivity } = deviceEntryUnsafe
const now = getRoundedTimestampForLastConnectivity()
if (parseInt(lastConnectivity, 10) !== now) {
@@ -115,8 +115,10 @@ export const createSyncRouter = ({ database, websocket, connectedDevicesManager,
return generateServerDataStatus({
database,
familyId,
+ deviceId,
clientStatus: body.status,
- transaction
+ transaction,
+ eventHandler
})
})
@@ -127,6 +129,10 @@ export const createSyncRouter = ({ database, websocket, connectedDevicesManager,
if (serverStatus.usedTimes) { eventHandler.countEvent('pullStatusRequest usedTimes') }
if (serverStatus.rules) { eventHandler.countEvent('pullStatusRequest rules') }
if (serverStatus.users) { eventHandler.countEvent('pullStatusRequest users') }
+ if (serverStatus.krq) { eventHandler.countEvent('pullStatusRequest pendingKeyRequests') }
+ if (serverStatus.kr) { eventHandler.countEvent('pullStatusRequest keyResponses') }
+ if (serverStatus.dh) { eventHandler.countEvent('pullStatusRequest dh') }
+ if (serverStatus.u2f) { eventHandler.countEvent('pullStatusRequest u2f') }
res.json(serverStatus)
} catch (ex) {
diff --git a/src/api/validator.ts b/src/api/validator.ts
index ee22472..408c934 100644
--- a/src/api/validator.ts
+++ b/src/api/validator.ts
@@ -1,6 +1,6 @@
// tslint:disable
-import { ClientPushChangesRequest, ClientPullChangesRequest, MailAuthTokenRequestBody, CreateFamilyByMailTokenRequest, SignIntoFamilyRequest, RecoverParentPasswordRequest, CanRecoverPasswordRequest, RegisterChildDeviceRequest, SerializedParentAction, SerializedAppLogicAction, SerializedChildAction, CreateRegisterDeviceTokenRequest, CanDoPurchaseRequest, FinishPurchaseByGooglePlayRequest, LinkParentMailAddressRequest, UpdatePrimaryDeviceRequest, RemoveDeviceRequest, RequestWithAuthToken, SendMailLoginCodeRequest, SignInByMailCodeRequest } from './schema'
-const Ajv = require('ajv')
+import { ClientPushChangesRequest, ClientPullChangesRequest, MailAuthTokenRequestBody, CreateFamilyByMailTokenRequest, SignIntoFamilyRequest, RecoverParentPasswordRequest, RegisterChildDeviceRequest, SerializedParentAction, SerializedAppLogicAction, SerializedChildAction, CreateRegisterDeviceTokenRequest, CanDoPurchaseRequest, FinishPurchaseByGooglePlayRequest, LinkParentMailAddressRequest, UpdatePrimaryDeviceRequest, RemoveDeviceRequest, RequestIdentityTokenRequest, RequestWithAuthToken, SendMailLoginCodeRequest, SignInByMailCodeRequest, IdentityTokenPayload, DeleteAccountPayload } from './schema'
+import Ajv from 'ajv'
const ajv = new Ajv()
const definitions = {
@@ -60,6 +60,24 @@ const definitions = {
},
"clientLevel": {
"type": "number"
+ },
+ "devicesDetail": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/DeviceDataStatus"
+ }
+ },
+ "kri": {
+ "type": "number"
+ },
+ "kr": {
+ "type": "number"
+ },
+ "dh": {
+ "type": "string"
+ },
+ "u2f": {
+ "type": "string"
}
},
"additionalProperties": false,
@@ -97,7 +115,19 @@ const definitions = {
"usedTime"
]
},
- "ParentPassword": {
+ "DeviceDataStatus": {
+ "type": "object",
+ "properties": {
+ "appsB": {
+ "type": "string"
+ },
+ "appsD": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "PlaintextParentPassword": {
"type": "object",
"properties": {
"hash": {
@@ -182,6 +212,29 @@ const definitions = {
"type"
]
},
+ "SerializedAddParentU2fKeyAction": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "ADD_PARENT_U2F"
+ ]
+ },
+ "keyHandle": {
+ "type": "string"
+ },
+ "publicKey": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "keyHandle",
+ "publicKey",
+ "type"
+ ]
+ },
"SerializedAddUserAction": {
"type": "object",
"properties": {
@@ -205,7 +258,7 @@ const definitions = {
"type": "string"
},
"password": {
- "$ref": "#/definitions/ParentPassword"
+ "$ref": "#/definitions/EncryptableParentPassword"
},
"timeZone": {
"type": "string"
@@ -220,6 +273,29 @@ const definitions = {
"userType"
]
},
+ "EncryptableParentPassword": {
+ "type": "object",
+ "properties": {
+ "hash": {
+ "type": "string"
+ },
+ "secondHash": {
+ "type": "string"
+ },
+ "secondSalt": {
+ "type": "string"
+ },
+ "encrypted": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "hash",
+ "secondHash",
+ "secondSalt"
+ ]
+ },
"SerializedChangeParentPasswordAction": {
"type": "object",
"properties": {
@@ -330,6 +406,9 @@ const definitions = {
},
"pause": {
"type": "number"
+ },
+ "perDay": {
+ "type": "boolean"
}
},
"additionalProperties": false,
@@ -439,6 +518,9 @@ const definitions = {
},
"ignoreHadManipulationFlags": {
"type": "number"
+ },
+ "ignoreManipulationFlags": {
+ "type": "number"
}
},
"additionalProperties": false,
@@ -479,6 +561,21 @@ const definitions = {
"type"
]
},
+ "SerializedReportU2fLoginAction": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "REPORT_U2F_LOGIN"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type"
+ ]
+ },
"SerializedRemoveCategoryAppsAction": {
"type": "object",
"properties": {
@@ -505,6 +602,29 @@ const definitions = {
"type"
]
},
+ "SerializedRemoveParentU2fKeyAction": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "REMOVE_PARENT_U2F"
+ ]
+ },
+ "keyHandle": {
+ "type": "string"
+ },
+ "publicKey": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "keyHandle",
+ "publicKey",
+ "type"
+ ]
+ },
"SerializedRemoveUserAction": {
"type": "object",
"properties": {
@@ -569,25 +689,6 @@ const definitions = {
"type"
]
},
- "SerializedResetParentBlockedTimesAction": {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "RESET_PARENT_BLOCKED_TIMES"
- ]
- },
- "parentId": {
- "type": "string"
- }
- },
- "additionalProperties": false,
- "required": [
- "parentId",
- "type"
- ]
- },
"SerializedReviewChildTaskAction": {
"type": "object",
"properties": {
@@ -605,6 +706,9 @@ const definitions = {
},
"time": {
"type": "number"
+ },
+ "day": {
+ "type": "number"
}
},
"additionalProperties": false,
@@ -677,7 +781,7 @@ const definitions = {
"type": "string"
},
"newPassword": {
- "$ref": "#/definitions/ParentPassword"
+ "$ref": "#/definitions/EncryptableParentPassword"
}
},
"additionalProperties": false,
@@ -956,6 +1060,9 @@ const definitions = {
},
"blocked": {
"type": "boolean"
+ },
+ "blockDelay": {
+ "type": "number"
}
},
"additionalProperties": false,
@@ -1011,6 +1118,33 @@ const definitions = {
"type"
]
},
+ "SerializedUpdateCategoryFlagsAction": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "UPDATE_CATEGORY_FLAGS"
+ ]
+ },
+ "categoryId": {
+ "type": "string"
+ },
+ "modified": {
+ "type": "number"
+ },
+ "values": {
+ "type": "number"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "categoryId",
+ "modified",
+ "type",
+ "values"
+ ]
+ },
"SerializedUpdateCategorySortingAction": {
"type": "object",
"properties": {
@@ -1076,6 +1210,9 @@ const definitions = {
},
"flags": {
"type": "number"
+ },
+ "minutes": {
+ "type": "number"
}
},
"additionalProperties": false,
@@ -1218,29 +1355,6 @@ const definitions = {
"type"
]
},
- "SerializedUpdateParentBlockedTimesAction": {
- "type": "object",
- "properties": {
- "type": {
- "type": "string",
- "enum": [
- "UPDATE_PARENT_BLOCKED_TIMES"
- ]
- },
- "parentId": {
- "type": "string"
- },
- "times": {
- "type": "string"
- }
- },
- "additionalProperties": false,
- "required": [
- "parentId",
- "times",
- "type"
- ]
- },
"SerializedUpdateParentNotificationFlagsAction": {
"type": "object",
"properties": {
@@ -1300,6 +1414,9 @@ const definitions = {
},
"pause": {
"type": "number"
+ },
+ "perDay": {
+ "type": "boolean"
}
},
"additionalProperties": false,
@@ -1360,6 +1477,29 @@ const definitions = {
"userId"
]
},
+ "SerializedUpdateUserLimitLoginPreBlockDuration": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "UPDATE_USER_LIMIT_LOGIN_PRE_BLOCK_DURATION"
+ ]
+ },
+ "userId": {
+ "type": "string"
+ },
+ "preBlockDuration": {
+ "type": "number"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "preBlockDuration",
+ "type",
+ "userId"
+ ]
+ },
"SerializedAddInstalledAppsAction": {
"type": "object",
"properties": {
@@ -1484,16 +1624,7 @@ const definitions = {
}
],
"minItems": 2,
- "additionalItems": {
- "anyOf": [
- {
- "type": "number"
- },
- {
- "type": "number"
- }
- ]
- }
+ "maxItems": 2
}
},
"sdl": {
@@ -1515,22 +1646,7 @@ const definitions = {
}
],
"minItems": 4,
- "additionalItems": {
- "anyOf": [
- {
- "type": "number"
- },
- {
- "type": "number"
- },
- {
- "type": "number"
- },
- {
- "type": "number"
- }
- ]
- }
+ "maxItems": 4
}
}
},
@@ -1553,6 +1669,25 @@ const definitions = {
"type"
]
},
+ "SerializedFinishKeyRequestAction": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "FINISH_KEY_REQUEST"
+ ]
+ },
+ "dsn": {
+ "type": "number"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "dsn",
+ "type"
+ ]
+ },
"SerializedForceSyncAction": {
"type": "object",
"properties": {
@@ -1568,6 +1703,37 @@ const definitions = {
"type"
]
},
+ "SerializedReplyToKeyRequestAction": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "REPLY_TO_KEY_REQUEST"
+ ]
+ },
+ "rsn": {
+ "type": "number"
+ },
+ "tempKey": {
+ "type": "string"
+ },
+ "encryptedKey": {
+ "type": "string"
+ },
+ "signature": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "encryptedKey",
+ "rsn",
+ "signature",
+ "tempKey",
+ "type"
+ ]
+ },
"SerializedMarkTaskPendingAction": {
"type": "object",
"properties": {
@@ -1587,6 +1753,31 @@ const definitions = {
"type"
]
},
+ "SerializedUpdateInstalledAppsAction": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "UPDATE_INSTALLED_APPS"
+ ]
+ },
+ "b": {
+ "type": "string"
+ },
+ "d": {
+ "type": "string"
+ },
+ "w": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "w"
+ ]
+ },
"SerializedRemoveInstalledAppsAction": {
"type": "object",
"properties": {
@@ -1609,6 +1800,43 @@ const definitions = {
"type"
]
},
+ "SerializedSendKeyRequestAction": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "SEND_KEY_REQUEST"
+ ]
+ },
+ "dsn": {
+ "type": "number"
+ },
+ "deviceId": {
+ "type": "string"
+ },
+ "categoryId": {
+ "type": "string"
+ },
+ "dataType": {
+ "type": "number"
+ },
+ "tempKey": {
+ "type": "string"
+ },
+ "signature": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "dataType",
+ "dsn",
+ "signature",
+ "tempKey",
+ "type"
+ ]
+ },
"SerializedSignOutAtDeviceAction": {
"type": "object",
"properties": {
@@ -1661,16 +1889,7 @@ const definitions = {
}
],
"minItems": 2,
- "additionalItems": {
- "anyOf": [
- {
- "type": "string"
- },
- {
- "type": "string"
- }
- ]
- }
+ "maxItems": 2
}
},
"updatedOrAdded": {
@@ -1760,6 +1979,15 @@ const definitions = {
},
"isQOrLaterNow": {
"type": "boolean"
+ },
+ "addedManipulationFlags": {
+ "type": "number"
+ },
+ "platformType": {
+ "type": "string"
+ },
+ "platformLevel": {
+ "type": "number"
}
},
"additionalProperties": false,
@@ -1767,6 +1995,25 @@ const definitions = {
"type"
]
},
+ "SerializedUploadDevicePublicKeyAction": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "UPLOAD_DEVICE_PUBLIC_KEY"
+ ]
+ },
+ "key": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "key",
+ "type"
+ ]
+ },
"SerializedChildChangePasswordAction": {
"type": "object",
"properties": {
@@ -1777,7 +2024,7 @@ const definitions = {
]
},
"password": {
- "$ref": "#/definitions/ParentPassword"
+ "$ref": "#/definitions/EncryptableParentPassword"
}
},
"additionalProperties": false,
@@ -1917,6 +2164,18 @@ const definitions = {
},
"qOrLater": {
"type": "boolean"
+ },
+ "mFlags": {
+ "type": "number"
+ },
+ "pk": {
+ "type": "string"
+ },
+ "pType": {
+ "type": "string"
+ },
+ "pLevel": {
+ "type": "number"
}
},
"additionalProperties": false,
@@ -1941,9 +2200,11 @@ const definitions = {
"hadManipulation",
"hadManipulationFlags",
"isUserKeptSignedIn",
+ "mFlags",
"model",
"name",
"networkTime",
+ "pLevel",
"qOrLater",
"reboot",
"rebootIsManipulation",
@@ -1978,6 +2239,40 @@ const definitions = {
],
"type": "string"
},
+ "ServerExtendedDeviceData": {
+ "type": "object",
+ "properties": {
+ "deviceId": {
+ "type": "string"
+ },
+ "appsBase": {
+ "$ref": "#/definitions/ServerCryptContainer"
+ },
+ "appsDiff": {
+ "$ref": "#/definitions/ServerCryptContainer"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "deviceId"
+ ]
+ },
+ "ServerCryptContainer": {
+ "type": "object",
+ "properties": {
+ "version": {
+ "type": "string"
+ },
+ "data": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "data",
+ "version"
+ ]
+ },
"ServerInstalledAppsData": {
"type": "object",
"properties": {
@@ -2064,17 +2359,32 @@ const definitions = {
},
"dlu": {
"type": "number"
+ },
+ "flags": {
+ "type": "number"
+ },
+ "blockNotificationDelay": {
+ "type": "number"
+ },
+ "atw": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
}
},
"additionalProperties": false,
"required": [
+ "atw",
"blockAllNotifications",
+ "blockNotificationDelay",
"blockedTimes",
"categoryId",
"childId",
"dlu",
"extraTime",
"extraTimeDay",
+ "flags",
"mblCharging",
"mblMobile",
"networks",
@@ -2267,6 +2577,9 @@ const definitions = {
},
"pause": {
"type": "number"
+ },
+ "perDay": {
+ "type": "boolean"
}
},
"additionalProperties": false,
@@ -2277,6 +2590,7 @@ const definitions = {
"id",
"maxTime",
"pause",
+ "perDay",
"session",
"start"
]
@@ -2402,6 +2716,9 @@ const definitions = {
},
"llc": {
"type": "string"
+ },
+ "pbd": {
+ "type": "number"
}
},
"additionalProperties": false,
@@ -2421,10 +2738,139 @@ const definitions = {
"timeZone",
"type"
]
+ },
+ "ServerKeyRequest": {
+ "type": "object",
+ "properties": {
+ "srvSeq": {
+ "type": "number"
+ },
+ "senId": {
+ "type": "string"
+ },
+ "senSeq": {
+ "type": "number"
+ },
+ "deviceId": {
+ "type": "string"
+ },
+ "categoryId": {
+ "type": "string"
+ },
+ "type": {
+ "type": "number"
+ },
+ "tempKey": {
+ "type": "string"
+ },
+ "signature": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "senId",
+ "senSeq",
+ "signature",
+ "srvSeq",
+ "tempKey",
+ "type"
+ ]
+ },
+ "ServerKeyResponse": {
+ "type": "object",
+ "properties": {
+ "srvSeq": {
+ "type": "number"
+ },
+ "sender": {
+ "type": "string"
+ },
+ "rqSeq": {
+ "type": "number"
+ },
+ "tempKey": {
+ "type": "string"
+ },
+ "cryptKey": {
+ "type": "string"
+ },
+ "signature": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "cryptKey",
+ "rqSeq",
+ "sender",
+ "signature",
+ "srvSeq",
+ "tempKey"
+ ]
+ },
+ "ServerDhKey": {
+ "type": "object",
+ "properties": {
+ "v": {
+ "type": "string"
+ },
+ "k": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "k",
+ "v"
+ ]
+ },
+ "U2fData": {
+ "type": "object",
+ "properties": {
+ "v": {
+ "type": "string"
+ },
+ "d": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/U2fItem"
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "d",
+ "v"
+ ]
+ },
+ "U2fItem": {
+ "type": "object",
+ "properties": {
+ "u": {
+ "type": "string"
+ },
+ "a": {
+ "type": "number"
+ },
+ "h": {
+ "type": "string"
+ },
+ "p": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "a",
+ "h",
+ "p",
+ "u"
+ ]
}
}
-export const isClientPushChangesRequest: (value: object) => value is ClientPushChangesRequest = ajv.compile({
+export const isClientPushChangesRequest: (value: unknown) => value is ClientPushChangesRequest = ajv.compile({
"type": "object",
"properties": {
"deviceAuthToken": {
@@ -2445,7 +2891,7 @@ export const isClientPushChangesRequest: (value: object) => value is ClientPushC
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isClientPullChangesRequest: (value: object) => value is ClientPullChangesRequest = ajv.compile({
+export const isClientPullChangesRequest: (value: unknown) => value is ClientPullChangesRequest = ajv.compile({
"type": "object",
"properties": {
"deviceAuthToken": {
@@ -2463,7 +2909,7 @@ export const isClientPullChangesRequest: (value: object) => value is ClientPullC
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isMailAuthTokenRequestBody: (value: object) => value is MailAuthTokenRequestBody = ajv.compile({
+export const isMailAuthTokenRequestBody: (value: unknown) => value is MailAuthTokenRequestBody = ajv.compile({
"type": "object",
"properties": {
"mailAuthToken": {
@@ -2477,14 +2923,14 @@ export const isMailAuthTokenRequestBody: (value: object) => value is MailAuthTok
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isCreateFamilyByMailTokenRequest: (value: object) => value is CreateFamilyByMailTokenRequest = ajv.compile({
+export const isCreateFamilyByMailTokenRequest: (value: unknown) => value is CreateFamilyByMailTokenRequest = ajv.compile({
"type": "object",
"properties": {
"mailAuthToken": {
"type": "string"
},
"parentPassword": {
- "$ref": "#/definitions/ParentPassword"
+ "$ref": "#/definitions/PlaintextParentPassword"
},
"parentDevice": {
"$ref": "#/definitions/NewDeviceInfo"
@@ -2497,6 +2943,9 @@ export const isCreateFamilyByMailTokenRequest: (value: object) => value is Creat
},
"parentName": {
"type": "string"
+ },
+ "clientLevel": {
+ "type": "number"
}
},
"additionalProperties": false,
@@ -2511,7 +2960,7 @@ export const isCreateFamilyByMailTokenRequest: (value: object) => value is Creat
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isSignIntoFamilyRequest: (value: object) => value is SignIntoFamilyRequest = ajv.compile({
+export const isSignIntoFamilyRequest: (value: unknown) => value is SignIntoFamilyRequest = ajv.compile({
"type": "object",
"properties": {
"mailAuthToken": {
@@ -2522,6 +2971,9 @@ export const isSignIntoFamilyRequest: (value: object) => value is SignIntoFamily
},
"deviceName": {
"type": "string"
+ },
+ "clientLevel": {
+ "type": "number"
}
},
"additionalProperties": false,
@@ -2533,14 +2985,14 @@ export const isSignIntoFamilyRequest: (value: object) => value is SignIntoFamily
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isRecoverParentPasswordRequest: (value: object) => value is RecoverParentPasswordRequest = ajv.compile({
+export const isRecoverParentPasswordRequest: (value: unknown) => value is RecoverParentPasswordRequest = ajv.compile({
"type": "object",
"properties": {
"mailAuthToken": {
"type": "string"
},
"password": {
- "$ref": "#/definitions/ParentPassword"
+ "$ref": "#/definitions/PlaintextParentPassword"
}
},
"additionalProperties": false,
@@ -2551,25 +3003,7 @@ export const isRecoverParentPasswordRequest: (value: object) => value is Recover
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isCanRecoverPasswordRequest: (value: object) => value is CanRecoverPasswordRequest = ajv.compile({
- "type": "object",
- "properties": {
- "mailAuthToken": {
- "type": "string"
- },
- "parentUserId": {
- "type": "string"
- }
- },
- "additionalProperties": false,
- "required": [
- "mailAuthToken",
- "parentUserId"
- ],
- "definitions": definitions,
- "$schema": "http://json-schema.org/draft-07/schema#"
-})
-export const isRegisterChildDeviceRequest: (value: object) => value is RegisterChildDeviceRequest = ajv.compile({
+export const isRegisterChildDeviceRequest: (value: unknown) => value is RegisterChildDeviceRequest = ajv.compile({
"type": "object",
"properties": {
"registerToken": {
@@ -2580,6 +3014,9 @@ export const isRegisterChildDeviceRequest: (value: object) => value is RegisterC
},
"deviceName": {
"type": "string"
+ },
+ "clientLevel": {
+ "type": "number"
}
},
"additionalProperties": false,
@@ -2591,7 +3028,7 @@ export const isRegisterChildDeviceRequest: (value: object) => value is RegisterC
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isSerializedParentAction: (value: object) => value is SerializedParentAction = ajv.compile({
+export const isSerializedParentAction: (value: unknown) => value is SerializedParentAction = ajv.compile({
"anyOf": [
{
"$ref": "#/definitions/SerializedAddCategoryAppsAction"
@@ -2599,6 +3036,9 @@ export const isSerializedParentAction: (value: object) => value is SerializedPar
{
"$ref": "#/definitions/SerializedAddCategoryNetworkIdAction"
},
+ {
+ "$ref": "#/definitions/SerializedAddParentU2fKeyAction"
+ },
{
"$ref": "#/definitions/SerializedAddUserAction"
},
@@ -2626,9 +3066,15 @@ export const isSerializedParentAction: (value: object) => value is SerializedPar
{
"$ref": "#/definitions/SerializedIncrementCategoryExtraTimeAction"
},
+ {
+ "$ref": "#/definitions/SerializedReportU2fLoginAction"
+ },
{
"$ref": "#/definitions/SerializedRemoveCategoryAppsAction"
},
+ {
+ "$ref": "#/definitions/SerializedRemoveParentU2fKeyAction"
+ },
{
"$ref": "#/definitions/SerializedRemoveUserAction"
},
@@ -2638,9 +3084,6 @@ export const isSerializedParentAction: (value: object) => value is SerializedPar
{
"$ref": "#/definitions/SerializeResetCategoryNetworkIdsAction"
},
- {
- "$ref": "#/definitions/SerializedResetParentBlockedTimesAction"
- },
{
"$ref": "#/definitions/SerializedReviewChildTaskAction"
},
@@ -2695,6 +3138,9 @@ export const isSerializedParentAction: (value: object) => value is SerializedPar
{
"$ref": "#/definitions/SerializedUpdatCategoryDisableLimitsAction"
},
+ {
+ "$ref": "#/definitions/SerializedUpdateCategoryFlagsAction"
+ },
{
"$ref": "#/definitions/SerializedUpdateCategorySortingAction"
},
@@ -2719,9 +3165,6 @@ export const isSerializedParentAction: (value: object) => value is SerializedPar
{
"$ref": "#/definitions/SerialiizedUpdateNetworkTimeVerificationAction"
},
- {
- "$ref": "#/definitions/SerializedUpdateParentBlockedTimesAction"
- },
{
"$ref": "#/definitions/SerializedUpdateParentNotificationFlagsAction"
},
@@ -2733,12 +3176,15 @@ export const isSerializedParentAction: (value: object) => value is SerializedPar
},
{
"$ref": "#/definitions/SerializedUpdateUserLimitLoginCategory"
+ },
+ {
+ "$ref": "#/definitions/SerializedUpdateUserLimitLoginPreBlockDuration"
}
],
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isSerializedAppLogicAction: (value: object) => value is SerializedAppLogicAction = ajv.compile({
+export const isSerializedAppLogicAction: (value: unknown) => value is SerializedAppLogicAction = ajv.compile({
"anyOf": [
{
"$ref": "#/definitions/SerializedAddInstalledAppsAction"
@@ -2749,15 +3195,27 @@ export const isSerializedAppLogicAction: (value: object) => value is SerializedA
{
"$ref": "#/definitions/SerializedAddUsedTimeActionVersion2"
},
+ {
+ "$ref": "#/definitions/SerializedFinishKeyRequestAction"
+ },
{
"$ref": "#/definitions/SerializedForceSyncAction"
},
+ {
+ "$ref": "#/definitions/SerializedReplyToKeyRequestAction"
+ },
{
"$ref": "#/definitions/SerializedMarkTaskPendingAction"
},
+ {
+ "$ref": "#/definitions/SerializedUpdateInstalledAppsAction"
+ },
{
"$ref": "#/definitions/SerializedRemoveInstalledAppsAction"
},
+ {
+ "$ref": "#/definitions/SerializedSendKeyRequestAction"
+ },
{
"$ref": "#/definitions/SerializedSignOutAtDeviceAction"
},
@@ -2769,12 +3227,15 @@ export const isSerializedAppLogicAction: (value: object) => value is SerializedA
},
{
"$ref": "#/definitions/SerializedUpdateDeviceStatusAction"
+ },
+ {
+ "$ref": "#/definitions/SerializedUploadDevicePublicKeyAction"
}
],
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isSerializedChildAction: (value: object) => value is SerializedChildAction = ajv.compile({
+export const isSerializedChildAction: (value: unknown) => value is SerializedChildAction = ajv.compile({
"anyOf": [
{
"$ref": "#/definitions/SerializedChildChangePasswordAction"
@@ -2786,7 +3247,7 @@ export const isSerializedChildAction: (value: object) => value is SerializedChil
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isCreateRegisterDeviceTokenRequest: (value: object) => value is CreateRegisterDeviceTokenRequest = ajv.compile({
+export const isCreateRegisterDeviceTokenRequest: (value: unknown) => value is CreateRegisterDeviceTokenRequest = ajv.compile({
"type": "object",
"properties": {
"deviceAuthToken": {
@@ -2808,7 +3269,7 @@ export const isCreateRegisterDeviceTokenRequest: (value: object) => value is Cre
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isCanDoPurchaseRequest: (value: object) => value is CanDoPurchaseRequest = ajv.compile({
+export const isCanDoPurchaseRequest: (value: unknown) => value is CanDoPurchaseRequest = ajv.compile({
"type": "object",
"properties": {
"type": {
@@ -2830,7 +3291,7 @@ export const isCanDoPurchaseRequest: (value: object) => value is CanDoPurchaseRe
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isFinishPurchaseByGooglePlayRequest: (value: object) => value is FinishPurchaseByGooglePlayRequest = ajv.compile({
+export const isFinishPurchaseByGooglePlayRequest: (value: unknown) => value is FinishPurchaseByGooglePlayRequest = ajv.compile({
"type": "object",
"properties": {
"deviceAuthToken": {
@@ -2852,7 +3313,7 @@ export const isFinishPurchaseByGooglePlayRequest: (value: object) => value is Fi
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isLinkParentMailAddressRequest: (value: object) => value is LinkParentMailAddressRequest = ajv.compile({
+export const isLinkParentMailAddressRequest: (value: unknown) => value is LinkParentMailAddressRequest = ajv.compile({
"type": "object",
"properties": {
"mailAuthToken": {
@@ -2878,7 +3339,7 @@ export const isLinkParentMailAddressRequest: (value: object) => value is LinkPar
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isUpdatePrimaryDeviceRequest: (value: object) => value is UpdatePrimaryDeviceRequest = ajv.compile({
+export const isUpdatePrimaryDeviceRequest: (value: unknown) => value is UpdatePrimaryDeviceRequest = ajv.compile({
"type": "object",
"properties": {
"action": {
@@ -2904,7 +3365,7 @@ export const isUpdatePrimaryDeviceRequest: (value: object) => value is UpdatePri
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isRemoveDeviceRequest: (value: object) => value is RemoveDeviceRequest = ajv.compile({
+export const isRemoveDeviceRequest: (value: unknown) => value is RemoveDeviceRequest = ajv.compile({
"type": "object",
"properties": {
"deviceAuthToken": {
@@ -2930,7 +3391,36 @@ export const isRemoveDeviceRequest: (value: object) => value is RemoveDeviceRequ
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isRequestWithAuthToken: (value: object) => value is RequestWithAuthToken = ajv.compile({
+export const isRequestIdentityTokenRequest: (value: unknown) => value is RequestIdentityTokenRequest = ajv.compile({
+ "type": "object",
+ "properties": {
+ "deviceAuthToken": {
+ "type": "string"
+ },
+ "parentUserId": {
+ "type": "string"
+ },
+ "parentPasswordSecondHash": {
+ "type": "string"
+ },
+ "purpose": {
+ "type": "string",
+ "enum": [
+ "purchase"
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "deviceAuthToken",
+ "parentPasswordSecondHash",
+ "parentUserId",
+ "purpose"
+ ],
+ "definitions": definitions,
+ "$schema": "http://json-schema.org/draft-07/schema#"
+})
+export const isRequestWithAuthToken: (value: unknown) => value is RequestWithAuthToken = ajv.compile({
"type": "object",
"properties": {
"deviceAuthToken": {
@@ -2944,7 +3434,7 @@ export const isRequestWithAuthToken: (value: object) => value is RequestWithAuth
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isSendMailLoginCodeRequest: (value: object) => value is SendMailLoginCodeRequest = ajv.compile({
+export const isSendMailLoginCodeRequest: (value: unknown) => value is SendMailLoginCodeRequest = ajv.compile({
"type": "object",
"properties": {
"mail": {
@@ -2952,6 +3442,9 @@ export const isSendMailLoginCodeRequest: (value: object) => value is SendMailLog
},
"locale": {
"type": "string"
+ },
+ "deviceAuthToken": {
+ "type": "string"
}
},
"additionalProperties": false,
@@ -2962,7 +3455,7 @@ export const isSendMailLoginCodeRequest: (value: object) => value is SendMailLog
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
-export const isSignInByMailCodeRequest: (value: object) => value is SignInByMailCodeRequest = ajv.compile({
+export const isSignInByMailCodeRequest: (value: unknown) => value is SignInByMailCodeRequest = ajv.compile({
"type": "object",
"properties": {
"mailLoginToken": {
@@ -2980,3 +3473,57 @@ export const isSignInByMailCodeRequest: (value: object) => value is SignInByMail
"definitions": definitions,
"$schema": "http://json-schema.org/draft-07/schema#"
})
+export const isIdentityTokenPayload: (value: unknown) => value is IdentityTokenPayload = ajv.compile({
+ "additionalProperties": false,
+ "type": "object",
+ "properties": {
+ "purpose": {
+ "type": "string",
+ "enum": [
+ "purchase"
+ ]
+ },
+ "familyId": {
+ "type": "string"
+ },
+ "userId": {
+ "type": "string"
+ },
+ "mail": {
+ "type": "string"
+ },
+ "exp": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "exp",
+ "familyId",
+ "mail",
+ "purpose",
+ "userId"
+ ],
+ "definitions": definitions,
+ "$schema": "http://json-schema.org/draft-07/schema#"
+})
+export const isDeleteAccountPayload: (value: unknown) => value is DeleteAccountPayload = ajv.compile({
+ "type": "object",
+ "properties": {
+ "deviceAuthToken": {
+ "type": "string"
+ },
+ "mailAuthTokens": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "deviceAuthToken",
+ "mailAuthTokens"
+ ],
+ "definitions": definitions,
+ "$schema": "http://json-schema.org/draft-07/schema#"
+})
diff --git a/src/config.ts b/src/config.ts
index 837581a..9cd9c40 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -21,6 +21,7 @@ interface Config {
disableSignup: boolean
pingInterval: number
alwaysPro: boolean
+ signSecret: string
}
function parseYesNo (value: string) {
@@ -33,11 +34,12 @@ function parseYesNo (value: string) {
}
}
+class ParseYesNoException extends Error {}
+
export const config: Config = {
mailWhitelist: (process.env.MAIL_WHITELIST || '').split(',').map((item) => item.trim()).filter((item) => item.length > 0),
disableSignup: parseYesNo(process.env.DISABLE_SIGNUP || 'no'),
pingInterval: parseInt(process.env.PING_INTERVAL_SEC || '25', 10) * 1000,
- alwaysPro: process.env.ALWAYS_PRO ? parseYesNo(process.env.ALWAYS_PRO) : false
+ alwaysPro: process.env.ALWAYS_PRO ? parseYesNo(process.env.ALWAYS_PRO) : false,
+ signSecret: process.env.SIGN_SECRET || ''
}
-
-class ParseYesNoException extends Error {}
diff --git a/src/connected-devices/index.ts b/src/connected-devices/index.ts
index 85b71ff..529edcf 100644
--- a/src/connected-devices/index.ts
+++ b/src/connected-devices/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -79,12 +79,12 @@ export class VisibleConnectedDevicesManager {
}): {
shutdown: () => void
} => {
- let observesDevices = new Set()
- let devicesWithSharingEnabled = new Set()
- let connectedDevices = new Set()
- let sentConnectedDevices = new Set()
+ const observesDevices = new Set()
+ const devicesWithSharingEnabled = new Set()
+ const connectedDevices = new Set()
+ const sentConnectedDevices = new Set()
let hasShutDown = false
- let shutdownHooks: Array<() => void> = []
+ const shutdownHooks: Array<() => void> = []
const shutdown = () => {
hasShutDown = true
@@ -97,7 +97,7 @@ export class VisibleConnectedDevicesManager {
return
}
- let result: Array = []
+ const result: Array = []
sentConnectedDevices.forEach((deviceId) => result.push(deviceId))
@@ -191,7 +191,7 @@ export class VisibleConnectedDevicesManager {
devices.forEach(({ deviceId, showDeviceConnected }) => {
addDevice({ deviceId, showDeviceConnected })
})
- })().catch((ex) => { /* ignore */ })
+ })().catch(() => { /* ignore */ })
{
// add all new devices + apply changes of sharing
diff --git a/src/database/adddevicetoken.ts b/src/database/adddevicetoken.ts
index fa25710..4d15e3e 100644
--- a/src/database/adddevicetoken.ts
+++ b/src/database/adddevicetoken.ts
@@ -26,7 +26,7 @@ export interface AddDeviceTokenAttributes {
createdAt: string
}
-export type AddDeviceTokenModel = Sequelize.Model & AddDeviceTokenAttributes
+export type AddDeviceTokenModel = Sequelize.Model & AddDeviceTokenAttributes
export type AddDeviceTokenModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): AddDeviceTokenModel;
}
diff --git a/src/database/app.ts b/src/database/app.ts
index 69f50c6..0b49eb3 100644
--- a/src/database/app.ts
+++ b/src/database/app.ts
@@ -29,7 +29,7 @@ export interface AppAttributes {
recommendation: AppRecommendation
}
-export type AppModel = Sequelize.Model & AppAttributes
+export type AppModel = Sequelize.Model & AppAttributes
export type AppModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): AppModel;
}
diff --git a/src/database/appactivity.ts b/src/database/appactivity.ts
index e23ab15..b8dd2f4 100644
--- a/src/database/appactivity.ts
+++ b/src/database/appactivity.ts
@@ -27,7 +27,7 @@ export interface AppActivityAttributes {
title: string
}
-export type AppActivityModel = Sequelize.Model & AppActivityAttributes
+export type AppActivityModel = Sequelize.Model & AppActivityAttributes
export type AppActivityModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): AppActivityModel;
}
diff --git a/src/database/authtoken.ts b/src/database/authtoken.ts
index 473a556..7f1e21a 100644
--- a/src/database/authtoken.ts
+++ b/src/database/authtoken.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -19,18 +19,24 @@ import * as Sequelize from 'sequelize'
import { authTokenColumn, timestampColumn } from './columns'
import { SequelizeAttributes } from './types'
-export interface AuthTokenAttributes {
+export interface AuthTokenAttributesVersion1 {
token: string
mail: string
createdAt: string
}
-export type AuthTokenModel = Sequelize.Model & AuthTokenAttributes
+export interface AuthTokenAttributesVersion2 {
+ locale: string
+}
+
+export type AuthTokenAttributes = AuthTokenAttributesVersion1 & AuthTokenAttributesVersion2
+
+export type AuthTokenModel = Sequelize.Model & AuthTokenAttributes
export type AuthTokenModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): AuthTokenModel;
}
-export const attributes: SequelizeAttributes = {
+export const attributesVersion1: SequelizeAttributes = {
token: {
...authTokenColumn,
primaryKey: true
@@ -45,4 +51,17 @@ export const attributes: SequelizeAttributes = {
createdAt: { ...timestampColumn }
}
+export const attributesVersion2: SequelizeAttributes = {
+ locale: {
+ type: Sequelize.STRING,
+ allowNull: false,
+ defaultValue: 'en'
+ }
+}
+
+export const attributes: SequelizeAttributes = {
+ ...attributesVersion1,
+ ...attributesVersion2
+}
+
export const createAuthtokenModel = (sequelize: Sequelize.Sequelize): AuthTokenModelStatic => sequelize.define('AuthToken', attributes) as AuthTokenModelStatic
diff --git a/src/database/category.ts b/src/database/category.ts
index 1233077..f5e415a 100644
--- a/src/database/category.ts
+++ b/src/database/category.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -22,6 +22,12 @@ import { SequelizeAttributes } from './types'
export const allowedTimeWarningFlags = 1 | 2 | 4 | 8 | 16
+export const categoryFlags = {
+ hasBlockedNetworkList: 1
+}
+
+export const maxCategoryFlags = categoryFlags.hasBlockedNetworkList
+
export interface CategoryAttributesVersion1 {
familyId: string
categoryId: string
@@ -54,7 +60,7 @@ export interface CategoryAttributesVersion5 {
}
export interface CategoryAttributesVersion6 {
- temporarilyBlockedEndTime: number
+ temporarilyBlockedEndTime: string
}
export interface CategoryAttributesVersion7 {
@@ -73,12 +79,21 @@ export interface CategoryAttributesVersion10 {
taskListVersion: string
}
+export interface CategoryAttributesVersion11 {
+ flags: string
+}
+
+export interface CategoryAttributesVersion12 {
+ blockNotificationDelay: string
+}
+
export type CategoryAttributes = CategoryAttributesVersion1 & CategoryAttributesVersion2 &
CategoryAttributesVersion3 & CategoryAttributesVersion4 & CategoryAttributesVersion5 &
CategoryAttributesVersion6 & CategoryAttributesVersion7 & CategoryAttributesVersion8 &
- CategoryAttributesVersion9 & CategoryAttributesVersion10
+ CategoryAttributesVersion9 & CategoryAttributesVersion10 & CategoryAttributesVersion11 &
+ CategoryAttributesVersion12
-export type CategoryModel = Sequelize.Model & CategoryAttributes
+export type CategoryModel = Sequelize.Model & CategoryAttributes
export type CategoryModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): CategoryModel;
}
@@ -210,6 +225,29 @@ export const attributesVersion10: SequelizeAttributes = {
+ flags: {
+ type: Sequelize.BIGINT,
+ allowNull: false,
+ defaultValue: 0,
+ validate: {
+ min: 0,
+ max: maxCategoryFlags
+ }
+ }
+}
+
+export const attributesVersion12: SequelizeAttributes = {
+ blockNotificationDelay: {
+ type: Sequelize.BIGINT,
+ allowNull: false,
+ defaultValue: 0,
+ validate: {
+ min: 0
+ }
+ }
+}
+
export const attributes: SequelizeAttributes = {
...attributesVersion1,
...attributesVersion2,
@@ -220,7 +258,9 @@ export const attributes: SequelizeAttributes = {
...attributesVersion7,
...attributesVersion8,
...attributesVersion9,
- ...attributesVersion10
+ ...attributesVersion10,
+ ...attributesVersion11,
+ ...attributesVersion12
}
export const createCategoryModel = (sequelize: Sequelize.Sequelize): CategoryModelStatic => sequelize.define('Category', attributes) as CategoryModelStatic
diff --git a/src/database/categoryapp.ts b/src/database/categoryapp.ts
index 9f71f01..9c02e68 100644
--- a/src/database/categoryapp.ts
+++ b/src/database/categoryapp.ts
@@ -25,7 +25,7 @@ export interface CategoryAppAttributes {
packageName: string
}
-export type CategoryAppModel = Sequelize.Model & CategoryAppAttributes
+export type CategoryAppModel = Sequelize.Model & CategoryAppAttributes
export type CategoryAppModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): CategoryAppModel;
}
diff --git a/src/database/categorynetworkid.ts b/src/database/categorynetworkid.ts
index 37c21c6..bf97067 100644
--- a/src/database/categorynetworkid.ts
+++ b/src/database/categorynetworkid.ts
@@ -26,7 +26,7 @@ export interface CategoryNetworkIdAttributes {
hashedNetworkId: string
}
-export type CategoryNetworkIdModel = Sequelize.Model & CategoryNetworkIdAttributes
+export type CategoryNetworkIdModel = Sequelize.Model & CategoryNetworkIdAttributes
export type CategoryNetworkIdModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): CategoryNetworkIdModel;
}
diff --git a/src/database/categorytimewarning.ts b/src/database/categorytimewarning.ts
new file mode 100644
index 0000000..525aeb4
--- /dev/null
+++ b/src/database/categorytimewarning.ts
@@ -0,0 +1,58 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { familyIdColumn, idWithinFamilyColumn } from './columns'
+import { SequelizeAttributes } from './types'
+
+export const categoryTimeWarningConstants = {
+ minMinutes: 1,
+ maxMinutes: 60 * 24 * 7 - 2
+}
+
+export interface CategoryTimeWarningAttributes {
+ familyId: string
+ categoryId: string
+ minutes: number
+}
+
+export type CategoryTimeWarningModel = Sequelize.Model & CategoryTimeWarningAttributes
+export type CategoryTimeWarningModelStatic = typeof Sequelize.Model & {
+ new (values?: object, options?: Sequelize.BuildOptions): CategoryTimeWarningModel;
+}
+
+export const attributes: SequelizeAttributes = {
+ familyId: {
+ ...familyIdColumn,
+ primaryKey: true
+ },
+ categoryId: {
+ ...idWithinFamilyColumn,
+ primaryKey: true
+ },
+ minutes: {
+ type: Sequelize.INTEGER,
+ allowNull: false,
+ validate: {
+ min: categoryTimeWarningConstants.minMinutes,
+ max: categoryTimeWarningConstants.maxMinutes
+ },
+ primaryKey: true
+ }
+}
+
+export const createCategoryTimeWarningModel = (sequelize: Sequelize.Sequelize): CategoryTimeWarningModelStatic => sequelize.define('CategoryTimeWarning', attributes) as CategoryTimeWarningModelStatic
diff --git a/src/database/childtask.ts b/src/database/childtask.ts
index 8fb9fde..73c409c 100644
--- a/src/database/childtask.ts
+++ b/src/database/childtask.ts
@@ -33,7 +33,7 @@ export interface ChildTaskAttributes {
export const maxExtraTime = 1000 * 60 * 60 * 24
export const maxTitleLength = 50
-export type ChildTaskModel = Sequelize.Model & ChildTaskAttributes
+export type ChildTaskModel = Sequelize.Model & ChildTaskAttributes
export type ChildTaskModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): ChildTaskModel;
}
diff --git a/src/database/config.ts b/src/database/config.ts
index 22d19f9..1563102 100644
--- a/src/database/config.ts
+++ b/src/database/config.ts
@@ -23,7 +23,7 @@ export interface ConfigAttributes {
value: string | null
}
-export type ConfigModel = Sequelize.Model & ConfigAttributes
+export type ConfigModel = Sequelize.Model & ConfigAttributes
export type ConfigModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): ConfigModel;
}
@@ -47,5 +47,6 @@ export const createConfigModel = (sequelize: Sequelize.Sequelize): ConfigModelSt
export const configItemIds = {
statusMessage: 'status_message',
- selfTestData: 'self_test_data'
+ selfTestData: 'self_test_data',
+ secondSelfTestData: 'self_test_data_two'
}
diff --git a/src/database/device.ts b/src/database/device.ts
index ba299ec..974c4b2 100644
--- a/src/database/device.ts
+++ b/src/database/device.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -32,6 +32,17 @@ export const DeviceHadManipulationFlags = {
ALL: 1 | 2 | 4 | 8 | 16 | 32
}
+export const DeviceManipulationFlags = {
+ USED_FGS_KILLER: 1,
+ ALL: 1
+}
+
+export const minPlatformTypeLength = 1
+export const maxPlatformTypeLength = 8
+
+export const minPlatformLevel = 0
+export const maxPlatformLevel = 128
+
export interface DeviceAttributesVersion1 {
familyId: string
deviceId: string
@@ -102,12 +113,31 @@ export interface DeviceAttributesVersion11 {
hadManipulationFlags: number
}
+export interface DeviceAttributesVersion12 {
+ manipulationFlags: number
+}
+
+export interface DeviceAttributesVersion13 {
+ publicKey: Buffer | null
+}
+
+export interface DeviceAttributesVersion14 {
+ nextKeyReplySequenceNumber: string
+}
+
+export interface DeviceAttributesVersion15 {
+ platformType: string | null
+ platformLevel: number
+}
+
export type DeviceAttributes = DeviceAttributesVersion1 & DeviceAttributesVersion2 &
DeviceAttributesVersion3 & DeviceAttributesVersion4 & DeviceAttributesVersion5 &
DeviceAttributesVersion6 & DeviceAttributesVersion7 & DeviceAttributesVersion8 &
- DeviceAttributesVersion9 & DeviceAttributesVersion10 & DeviceAttributesVersion11
+ DeviceAttributesVersion9 & DeviceAttributesVersion10 & DeviceAttributesVersion11 &
+ DeviceAttributesVersion12 & DeviceAttributesVersion13 & DeviceAttributesVersion14 &
+ DeviceAttributesVersion15
-export type DeviceModel = Sequelize.Model & DeviceAttributes
+export type DeviceModel = Sequelize.Model & DeviceAttributes
export type DeviceModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): DeviceModel;
}
@@ -259,6 +289,54 @@ export const attributesVersion11: SequelizeAttributes
}
}
+export const attributesVersion12: SequelizeAttributes = {
+ manipulationFlags: {
+ type: Sequelize.INTEGER,
+ allowNull: false,
+ defaultValue: 0,
+ validate: {
+ min: 0,
+ max: DeviceManipulationFlags.ALL
+ }
+ }
+}
+
+export const attributesVersion13: SequelizeAttributes = {
+ publicKey: {
+ type: Sequelize.BLOB,
+ allowNull: true,
+ defaultValue: null
+ }
+}
+
+export const attributesVersion14: SequelizeAttributes = {
+ nextKeyReplySequenceNumber: {
+ type: Sequelize.BIGINT,
+ allowNull: false,
+ defaultValue: 1
+ }
+}
+
+export const attributesVersion15: SequelizeAttributes = {
+ platformType: {
+ type: Sequelize.STRING(maxPlatformTypeLength),
+ allowNull: true,
+ defaultValue: null,
+ validate: {
+ len: [minPlatformTypeLength, maxPlatformTypeLength]
+ }
+ },
+ platformLevel: {
+ type: Sequelize.INTEGER,
+ allowNull: false,
+ defaultValue: minPlatformLevel,
+ validate: {
+ min: minPlatformLevel,
+ max: maxPlatformLevel
+ }
+ }
+}
+
export const attributes: SequelizeAttributes = {
...attributesVersion1,
...attributesVersion2,
@@ -270,7 +348,11 @@ export const attributes: SequelizeAttributes = {
...attributesVersion8,
...attributesVersion9,
...attributesVersion10,
- ...attributesVersion11
+ ...attributesVersion11,
+ ...attributesVersion12,
+ ...attributesVersion13,
+ ...attributesVersion14,
+ ...attributesVersion15
}
export const createDeviceModel = (sequelize: Sequelize.Sequelize): DeviceModelStatic => sequelize.define('Device', attributes) as DeviceModelStatic
@@ -291,7 +373,8 @@ export const hasDeviceManipulation = (device: DeviceAttributes) => {
manipulationOfOverlayPermission ||
manipulationOfAsPermission
- const hasAnyManipulation = hasActiveManipulationWarning || device.hadManipulation
+ const hasAnyManipulation = hasActiveManipulationWarning || device.hadManipulation ||
+ device.manipulationFlags !== 0
return hasAnyManipulation
}
diff --git a/src/database/devicedhkey.ts b/src/database/devicedhkey.ts
new file mode 100644
index 0000000..d04a700
--- /dev/null
+++ b/src/database/devicedhkey.ts
@@ -0,0 +1,100 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2024 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { familyIdColumn, idWithinFamilyColumn, versionColumn, timestampColumn } from './columns'
+import { SequelizeAttributes } from './types'
+
+export const config = {
+ generateNewKeyAfterAge: 1000 * 60 * 60 * 24,
+ generationTimeRounding: 1000 * 60 * 60,
+ expireDelay: 1000 * 60 * 60 * 2,
+ expireTimeRounding: 1000 * 60 * 15
+}
+
+export function calculateExpireTime(now: bigint): bigint {
+ const expireBaseTime = now + BigInt(config.expireDelay)
+ const expireTime = expireBaseTime - expireBaseTime % BigInt(config.expireTimeRounding) + BigInt(config.expireTimeRounding)
+
+ return expireTime
+}
+
+interface DeviceDhKeyAttributesVersion1 {
+ familyId: string
+ deviceId: string
+ version: string
+ createdAt: string
+ expireAt: string | null
+ publicKey: Buffer
+ privateKey: Buffer
+}
+
+interface DeviceDhKeyAttributesVersion2 {
+ createdAtSubsequence: number
+}
+
+export type DeviceDhKeyAttributes = DeviceDhKeyAttributesVersion1 & DeviceDhKeyAttributesVersion2
+
+export type DeviceDhKeyModel = Sequelize.Model & DeviceDhKeyAttributes
+export type DeviceDhKeyModelStatic = typeof Sequelize.Model & {
+ new (values?: object, options?: Sequelize.BuildOptions): DeviceDhKeyModel;
+}
+
+export const attributesVersion1: SequelizeAttributes = {
+ familyId: {
+ ...familyIdColumn,
+ primaryKey: true
+ },
+ deviceId: {
+ ...idWithinFamilyColumn,
+ primaryKey: true
+ },
+ version: {
+ ...versionColumn,
+ primaryKey: true
+ },
+ createdAt: {
+ ...timestampColumn
+ },
+ expireAt: {
+ ...timestampColumn,
+ allowNull: true
+ },
+ publicKey: {
+ type: Sequelize.BLOB,
+ allowNull: false
+ },
+ privateKey: {
+ type: Sequelize.BLOB,
+ allowNull: false
+ }
+}
+
+export const attributesVersion2: SequelizeAttributes = {
+ createdAtSubsequence: {
+ type: Sequelize.INTEGER,
+ allowNull: false,
+ defaultValue: 0
+ }
+}
+
+export const attributes: SequelizeAttributes = {
+ ...attributesVersion1,
+ ...attributesVersion2
+}
+
+export const createDeviceDhKey = (sequelize: Sequelize.Sequelize): DeviceDhKeyModelStatic => sequelize.define('DeviceDhKey', attributes) as DeviceDhKeyModelStatic
diff --git a/src/database/encryptedapplist.ts b/src/database/encryptedapplist.ts
new file mode 100644
index 0000000..cd3f88c
--- /dev/null
+++ b/src/database/encryptedapplist.ts
@@ -0,0 +1,66 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { familyIdColumn, idWithinFamilyColumn, versionColumn } from './columns'
+import { SequelizeAttributes } from './types'
+
+export interface EncryptedAppListAttributes {
+ familyId: string
+ deviceId: string
+ type: number
+ version: string
+ data: Buffer
+}
+
+export const types = {
+ base: 1,
+ diff: 2
+}
+
+export type EncryptedAppListModel = Sequelize.Model & EncryptedAppListAttributes
+export type EncryptedAppListModelStatic = typeof Sequelize.Model & {
+ new (values?: object, options?: Sequelize.BuildOptions): EncryptedAppListModel;
+}
+
+export const attributes: SequelizeAttributes = {
+ familyId: {
+ ...familyIdColumn,
+ primaryKey: true
+ },
+ deviceId: {
+ ...idWithinFamilyColumn,
+ primaryKey: true
+ },
+ type: {
+ type: Sequelize.INTEGER,
+ primaryKey: true,
+ validate: {
+ min: 1,
+ max: 2
+ }
+ },
+ version: {
+ ...versionColumn
+ },
+ data: {
+ type: Sequelize.BLOB,
+ allowNull: false
+ }
+}
+
+export const createEncryptedAppListModel = (sequelize: Sequelize.Sequelize): EncryptedAppListModelStatic => sequelize.define('EncryptedAppList', attributes) as EncryptedAppListModelStatic
diff --git a/src/database/family.ts b/src/database/family.ts
index 05c9d68..c58aac1 100644
--- a/src/database/family.ts
+++ b/src/database/family.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -19,7 +19,7 @@ import * as Sequelize from 'sequelize'
import { booleanColumn, familyIdColumn, optionalLabelColumn, timestampColumn, versionColumn } from './columns'
import { SequelizeAttributes } from './types'
-export interface FamilyAttributes {
+export interface FamilyAttributesVersion1 {
familyId: string
name: string
createdAt: string
@@ -29,12 +29,23 @@ export interface FamilyAttributes {
hasFullVersion: boolean
}
-export type FamilyModel = Sequelize.Model & FamilyAttributes
+export interface FamilyAttributesVersion2 {
+ nextServerKeyRequestSeq: string
+}
+
+export interface FamilyAttributesVersion3 {
+ u2fKeysVersion: string
+}
+
+export type FamilyAttributes = FamilyAttributesVersion1 &
+ FamilyAttributesVersion2 & FamilyAttributesVersion3
+
+export type FamilyModel = Sequelize.Model & FamilyAttributes
export type FamilyModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): FamilyModel;
}
-export const attributes: SequelizeAttributes = {
+export const attributesVersion1: SequelizeAttributes = {
familyId: {
...familyIdColumn,
primaryKey: true
@@ -47,4 +58,28 @@ export const attributes: SequelizeAttributes = {
hasFullVersion: { ...booleanColumn }
}
+export const attributesVersion2: SequelizeAttributes = {
+ nextServerKeyRequestSeq: {
+ type: Sequelize.BIGINT,
+ allowNull: false,
+ defaultValue: 1,
+ validate: {
+ min: 1
+ }
+ }
+}
+
+export const attributesVersion3: SequelizeAttributes = {
+ u2fKeysVersion: {
+ ...versionColumn,
+ defaultValue: '0000'
+ }
+}
+
+export const attributes: SequelizeAttributes = {
+ ...attributesVersion1,
+ ...attributesVersion2,
+ ...attributesVersion3
+}
+
export const createFamilyModel = (sequelize: Sequelize.Sequelize): FamilyModelStatic => sequelize.define('Family', attributes) as FamilyModelStatic
diff --git a/src/database/index.ts b/src/database/index.ts
index fd9c6f0..d1e5813 100644
--- a/src/database/index.ts
+++ b/src/database/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,134 +15,6 @@
* along with this program. If not, see .
*/
-import { Promise as BluePromise } from 'bluebird'
-import * as Sequelize from 'sequelize'
-import { generateIdWithinFamily } from '../util/token'
-import { AddDeviceTokenModelStatic, createAddDeviceTokenModel } from './adddevicetoken'
-import { AppModelStatic, createAppModel } from './app'
-import { AppActivityModelStatic, createAppActivityModel } from './appactivity'
-import { AuthTokenModelStatic, createAuthtokenModel } from './authtoken'
-import { CategoryModelStatic, createCategoryModel } from './category'
-import { CategoryAppModelStatic, createCategoryAppModel } from './categoryapp'
-import { CategoryNetworkIdModelStatic, createCategoryNetworkIdModel } from './categorynetworkid'
-import { ChildTaskModelStatic, createChildTaskModel } from './childtask'
-import { configItemIds, ConfigModelStatic, createConfigModel } from './config'
-import { createDeviceModel, DeviceModelStatic } from './device'
-import { createFamilyModel, FamilyModelStatic } from './family'
-import { createMailLoginTokenModel, MailLoginTokenModelStatic } from './maillogintoken'
-import { createUmzug } from './migration/umzug'
-import { createOldDeviceModel, OldDeviceModelStatic } from './olddevice'
-import { createPurchaseModel, PurchaseModelStatic } from './purchase'
-import { createSessionDurationModel, SessionDurationModelStatic } from './sessionduration'
-import { createTimelimitRuleModel, TimelimitRuleModelStatic } from './timelimitrule'
-import { createUsedTimeModel, UsedTimeModelStatic } from './usedtime'
-import { createUserModel, UserModelStatic } from './user'
-import { createUserLimitLoginCategoryModel, UserLimitLoginCategoryModelStatic } from './userlimitlogincategory'
-
-export type Transaction = Sequelize.Transaction
-
-export interface Database {
- addDeviceToken: AddDeviceTokenModelStatic
- authtoken: AuthTokenModelStatic
- app: AppModelStatic
- appActivity: AppActivityModelStatic
- category: CategoryModelStatic
- categoryApp: CategoryAppModelStatic
- categoryNetworkId: CategoryNetworkIdModelStatic
- childTask: ChildTaskModelStatic
- config: ConfigModelStatic
- device: DeviceModelStatic
- family: FamilyModelStatic
- mailLoginToken: MailLoginTokenModelStatic
- oldDevice: OldDeviceModelStatic
- purchase: PurchaseModelStatic
- sessionDuration: SessionDurationModelStatic
- timelimitRule: TimelimitRuleModelStatic
- usedTime: UsedTimeModelStatic
- user: UserModelStatic
- userLimitLoginCategory: UserLimitLoginCategoryModelStatic
- transaction: (autoCallback: (t: Transaction) => Promise, options?: { transaction: Transaction }) => Promise
- dialect: string
-}
-
-const createDatabase = (sequelize: Sequelize.Sequelize): Database => ({
- addDeviceToken: createAddDeviceTokenModel(sequelize),
- authtoken: createAuthtokenModel(sequelize),
- app: createAppModel(sequelize),
- appActivity: createAppActivityModel(sequelize),
- category: createCategoryModel(sequelize),
- categoryApp: createCategoryAppModel(sequelize),
- childTask: createChildTaskModel(sequelize),
- categoryNetworkId: createCategoryNetworkIdModel(sequelize),
- config: createConfigModel(sequelize),
- device: createDeviceModel(sequelize),
- family: createFamilyModel(sequelize),
- mailLoginToken: createMailLoginTokenModel(sequelize),
- oldDevice: createOldDeviceModel(sequelize),
- purchase: createPurchaseModel(sequelize),
- sessionDuration: createSessionDurationModel(sequelize),
- timelimitRule: createTimelimitRuleModel(sequelize),
- usedTime: createUsedTimeModel(sequelize),
- user: createUserModel(sequelize),
- userLimitLoginCategory: createUserLimitLoginCategoryModel(sequelize),
- transaction: (autoCallback: (transaction: Transaction) => Promise, options?: { transaction: Transaction }) => (sequelize.transaction({
- isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED,
- transaction: options?.transaction
- }, autoCallback) as any) as Promise,
- dialect: sequelize.getDialect()
-})
-
-export const sequelize = new Sequelize.Sequelize(process.env.DATABASE_URL || 'sqlite://test.db', {
- define: {
- timestamps: false
- },
- logging: false
-})
-
-export const defaultDatabase = createDatabase(sequelize)
-export const defaultUmzug = createUmzug(sequelize)
-
-class NestedTransactionTestException extends Error {}
-class TestRollbackException extends NestedTransactionTestException {}
-class NestedTransactionsNotWorkingException extends NestedTransactionTestException { constructor () { super('NestedTransactionsNotWorkingException') } }
-class IllegalStateException extends NestedTransactionTestException {}
-
-export const wrapPromise = (promise: Promise) => BluePromise.resolve(promise)
-export const warpPromiseReturner = (fun: () => Promise) => () => wrapPromise(fun())
-
-export async function assertNestedTransactionsAreWorking (database: Database) {
- const testValue = generateIdWithinFamily()
-
- // clean up just for the case
- await database.config.destroy({ where: { id: configItemIds.selfTestData } })
-
- await database.transaction(async (transaction) => {
- const readOne = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
-
- if (readOne) throw new IllegalStateException()
-
- await database.transaction(async (transaction) => {
- await database.config.create({ id: configItemIds.selfTestData, value: testValue }, { transaction })
-
- const readTwo = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
-
- if (readTwo?.value !== testValue) throw new IllegalStateException()
-
- try {
- await database.transaction(async (transaction) => {
- await database.config.destroy({ where: { id: configItemIds.selfTestData }, transaction })
-
- throw new TestRollbackException()
- }, { transaction })
- } catch (ex) {
- if (!(ex instanceof TestRollbackException)) throw ex
- }
-
- const readThree = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
-
- if (readThree?.value !== testValue) throw new NestedTransactionsNotWorkingException()
-
- await database.config.destroy({ where: { id: configItemIds.selfTestData }, transaction })
- }, { transaction })
- })
-}
+export { Transaction, Database, defaultDatabase, defaultUmzug } from './main'
+export { assertNestedTransactionsAreWorking } from './utils/nested-transactions'
+export { assertSerializeableTransactionsAreWorking, shouldRetryWithException } from './utils/serialized'
diff --git a/src/database/keyrequest.ts b/src/database/keyrequest.ts
new file mode 100644
index 0000000..70a068a
--- /dev/null
+++ b/src/database/keyrequest.ts
@@ -0,0 +1,87 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { familyIdColumn, idWithinFamilyColumn } from './columns'
+import { SequelizeAttributes } from './types'
+
+export interface KeyRequestAttributes {
+ familyId: string
+ serverSequenceNumber: string
+ senderDeviceId: string
+ senderSequenceNumber: string
+ deviceId: string | null
+ categoryId: string | null
+ type: number
+ tempKey: Buffer
+ signature: Buffer
+}
+
+export const types = {
+ appListBase: 1,
+ appListDiff: 2,
+ all: [1, 2]
+}
+
+export type KeyRequestModel = Sequelize.Model & KeyRequestAttributes
+export type KeyRequestModelStatic = typeof Sequelize.Model & {
+ new (values?: object, options?: Sequelize.BuildOptions): KeyRequestModel;
+}
+
+export const attributes: SequelizeAttributes = {
+ familyId: {
+ ...familyIdColumn,
+ primaryKey: true
+ },
+ serverSequenceNumber: {
+ type: Sequelize.BIGINT,
+ primaryKey: true,
+ allowNull: false
+ },
+ senderDeviceId: {
+ ...idWithinFamilyColumn
+ },
+ senderSequenceNumber: {
+ type: Sequelize.BIGINT,
+ allowNull: false
+ },
+ deviceId: {
+ ...idWithinFamilyColumn,
+ allowNull: true
+ },
+ categoryId: {
+ ...idWithinFamilyColumn,
+ allowNull: true
+ },
+ type: {
+ type: Sequelize.INTEGER,
+ allowNull: false,
+ validate: {
+ isIn: [types.all]
+ }
+ },
+ tempKey: {
+ type: Sequelize.BLOB,
+ allowNull: false
+ },
+ signature: {
+ type: Sequelize.BLOB,
+ allowNull: false
+ }
+}
+
+export const createKeyRequestModel = (sequelize: Sequelize.Sequelize): KeyRequestModelStatic => sequelize.define('KeyRequest', attributes) as KeyRequestModelStatic
diff --git a/src/database/keyresponse.ts b/src/database/keyresponse.ts
new file mode 100644
index 0000000..01edaed
--- /dev/null
+++ b/src/database/keyresponse.ts
@@ -0,0 +1,77 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { familyIdColumn, idWithinFamilyColumn } from './columns'
+import { SequelizeAttributes } from './types'
+
+export interface KeyResponseAttributes {
+ familyId: string
+ receiverDeviceId: string
+ requestServerSequenceNumber: string // fk to request table with familyId
+ senderDeviceId: string // pk up to this
+ replyServerSequenceNumber: string // unique with familyId, receiverDeviceId
+ requestClientSequenceNumber: string
+ tempKey: Buffer
+ encryptedKey: Buffer
+ signature: Buffer
+}
+
+export type KeyResponseModel = Sequelize.Model & KeyResponseAttributes
+export type KeyResponseModelStatic = typeof Sequelize.Model & {
+ new (values?: object, options?: Sequelize.BuildOptions): KeyResponseModel;
+}
+
+export const attributes: SequelizeAttributes = {
+ familyId: {
+ ...familyIdColumn,
+ primaryKey: true
+ },
+ receiverDeviceId: {
+ ...idWithinFamilyColumn
+ },
+ requestServerSequenceNumber: {
+ type: Sequelize.BIGINT,
+ primaryKey: true,
+ allowNull: false
+ },
+ senderDeviceId: {
+ ...idWithinFamilyColumn
+ },
+ replyServerSequenceNumber: {
+ type: Sequelize.BIGINT,
+ allowNull: false
+ },
+ requestClientSequenceNumber: {
+ type: Sequelize.BIGINT,
+ allowNull: false
+ },
+ tempKey: {
+ type: Sequelize.BLOB,
+ allowNull: false
+ },
+ encryptedKey: {
+ type: Sequelize.BLOB,
+ allowNull: false
+ },
+ signature: {
+ type: Sequelize.BLOB,
+ allowNull: false
+ }
+}
+
+export const createKeyResponseModel = (sequelize: Sequelize.Sequelize): KeyResponseModelStatic => sequelize.define('KeyResponse', attributes) as KeyResponseModelStatic
diff --git a/src/database/maillogintoken.ts b/src/database/maillogintoken.ts
index ae16a94..ed3b0a7 100644
--- a/src/database/maillogintoken.ts
+++ b/src/database/maillogintoken.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -19,7 +19,7 @@ import * as Sequelize from 'sequelize'
import { authTokenColumn, timestampColumn } from './columns'
import { SequelizeAttributes } from './types'
-export interface MailLoginTokenAttributes {
+export interface MailLoginTokenAttributesVersion1 {
mailLoginToken: string
receivedCode: string
mail: string
@@ -27,12 +27,18 @@ export interface MailLoginTokenAttributes {
remainingAttempts: number
}
-export type MailLoginTokenModel = Sequelize.Model & MailLoginTokenAttributes
+export interface MailLoginTokenAttributesVersion2 {
+ locale: string
+}
+
+export type MailLoginTokenAttributes = MailLoginTokenAttributesVersion1 & MailLoginTokenAttributesVersion2
+
+export type MailLoginTokenModel = Sequelize.Model & MailLoginTokenAttributes
export type MailLoginTokenModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): MailLoginTokenModel;
}
-export const attributes: SequelizeAttributes = {
+export const attributesVersion1: SequelizeAttributes = {
mailLoginToken: {
...authTokenColumn,
primaryKey: true
@@ -61,4 +67,17 @@ export const attributes: SequelizeAttributes = {
}
}
+export const attributesVersion2: SequelizeAttributes = {
+ locale: {
+ type: Sequelize.STRING,
+ allowNull: false,
+ defaultValue: 'en'
+ }
+}
+
+export const attributes: SequelizeAttributes = {
+ ...attributesVersion1,
+ ...attributesVersion2
+}
+
export const createMailLoginTokenModel = (sequelize: Sequelize.Sequelize): MailLoginTokenModelStatic => sequelize.define('MailLoginToken', attributes) as MailLoginTokenModelStatic
diff --git a/src/database/main.ts b/src/database/main.ts
new file mode 100644
index 0000000..2a823d9
--- /dev/null
+++ b/src/database/main.ts
@@ -0,0 +1,151 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { AddDeviceTokenModelStatic, createAddDeviceTokenModel } from './adddevicetoken'
+import { AuthTokenModelStatic, createAuthtokenModel } from './authtoken'
+import { CategoryModelStatic, createCategoryModel } from './category'
+import { CategoryAppModelStatic, createCategoryAppModel } from './categoryapp'
+import { CategoryNetworkIdModelStatic, createCategoryNetworkIdModel } from './categorynetworkid'
+import { CategoryTimeWarningModelStatic, createCategoryTimeWarningModel } from './categorytimewarning'
+import { ChildTaskModelStatic, createChildTaskModel } from './childtask'
+import { ConfigModelStatic, createConfigModel } from './config'
+import { createDeviceModel, DeviceModelStatic } from './device'
+import { createDeviceDhKey, DeviceDhKeyModelStatic } from './devicedhkey'
+import { createEncryptedAppListModel, EncryptedAppListModelStatic } from './encryptedapplist'
+import { createFamilyModel, FamilyModelStatic } from './family'
+import { createKeyRequestModel, KeyRequestModelStatic } from './keyrequest'
+import { createKeyResponseModel, KeyResponseModelStatic } from './keyresponse'
+import { createMailLoginTokenModel, MailLoginTokenModelStatic } from './maillogintoken'
+import { createUmzug } from './migration/umzug'
+import { createOldDeviceModel, OldDeviceModelStatic } from './olddevice'
+import { createPurchaseModel, PurchaseModelStatic } from './purchase'
+import { createSessionDurationModel, SessionDurationModelStatic } from './sessionduration'
+import { createTimelimitRuleModel, TimelimitRuleModelStatic } from './timelimitrule'
+import { createU2fKeyModel, U2fKeyModelStatic } from './u2fkey'
+import { createUsedTimeModel, UsedTimeModelStatic } from './usedtime'
+import { createUserModel, UserModelStatic } from './user'
+import { createUserLimitLoginCategoryModel, UserLimitLoginCategoryModelStatic } from './userlimitlogincategory'
+import { shouldRetryWithException } from './utils/serialized'
+
+export type Transaction = Sequelize.Transaction
+
+export interface Database {
+ addDeviceToken: AddDeviceTokenModelStatic
+ authtoken: AuthTokenModelStatic
+ category: CategoryModelStatic
+ categoryApp: CategoryAppModelStatic
+ categoryNetworkId: CategoryNetworkIdModelStatic
+ categoryTimeWarning: CategoryTimeWarningModelStatic
+ childTask: ChildTaskModelStatic
+ config: ConfigModelStatic
+ device: DeviceModelStatic
+ deviceDhKey: DeviceDhKeyModelStatic
+ encryptedAppList: EncryptedAppListModelStatic
+ family: FamilyModelStatic
+ keyRequest: KeyRequestModelStatic
+ keyResponse: KeyResponseModelStatic
+ mailLoginToken: MailLoginTokenModelStatic
+ oldDevice: OldDeviceModelStatic
+ purchase: PurchaseModelStatic
+ sessionDuration: SessionDurationModelStatic
+ timelimitRule: TimelimitRuleModelStatic
+ u2fKey: U2fKeyModelStatic
+ usedTime: UsedTimeModelStatic
+ user: UserModelStatic
+ userLimitLoginCategory: UserLimitLoginCategoryModelStatic
+ transaction: (
+ autoCallback: (t: Transaction) => Promise,
+ options?: TransactionOptions
+ ) => Promise
+ dialect: string
+}
+
+interface TransactionOptions {
+ transaction?: Transaction
+ disableRetry?: boolean
+}
+
+const createDatabase = (sequelize: Sequelize.Sequelize): Database => ({
+ addDeviceToken: createAddDeviceTokenModel(sequelize),
+ authtoken: createAuthtokenModel(sequelize),
+ category: createCategoryModel(sequelize),
+ categoryApp: createCategoryAppModel(sequelize),
+ childTask: createChildTaskModel(sequelize),
+ categoryNetworkId: createCategoryNetworkIdModel(sequelize),
+ categoryTimeWarning: createCategoryTimeWarningModel(sequelize),
+ config: createConfigModel(sequelize),
+ device: createDeviceModel(sequelize),
+ deviceDhKey: createDeviceDhKey(sequelize),
+ encryptedAppList: createEncryptedAppListModel(sequelize),
+ family: createFamilyModel(sequelize),
+ keyRequest: createKeyRequestModel(sequelize),
+ keyResponse: createKeyResponseModel(sequelize),
+ mailLoginToken: createMailLoginTokenModel(sequelize),
+ oldDevice: createOldDeviceModel(sequelize),
+ purchase: createPurchaseModel(sequelize),
+ sessionDuration: createSessionDurationModel(sequelize),
+ timelimitRule: createTimelimitRuleModel(sequelize),
+ u2fKey: createU2fKeyModel(sequelize),
+ usedTime: createUsedTimeModel(sequelize),
+ user: createUserModel(sequelize),
+ userLimitLoginCategory: createUserLimitLoginCategoryModel(sequelize),
+ async transaction(
+ autoCallback: (transaction: Transaction) => Promise,
+ options?: TransactionOptions
+ ): Promise {
+ const runAttempt = () => sequelize.transaction({
+ isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE,
+ transaction: options?.transaction
+ }, autoCallback)
+
+ const delay = (time: number) => new Promise((resolve) => setTimeout(resolve, time))
+
+ try {
+ return await runAttempt()
+ } catch (ex) {
+ if (
+ options?.disableRetry ||
+ options?.transaction ||
+ !shouldRetryWithException(this, ex)
+ ) throw ex
+ }
+
+ await delay(10 * (1 + Math.random()))
+
+ try {
+ return await runAttempt()
+ } catch (ex) {
+ if (!shouldRetryWithException(this, ex)) throw ex
+ }
+
+ await delay(100 * (1 + Math.random()))
+
+ return await runAttempt()
+ },
+ dialect: sequelize.getDialect()
+})
+
+export const sequelize = new Sequelize.Sequelize(process.env.DATABASE_URL || 'sqlite://test.db', {
+ define: {
+ timestamps: false
+ },
+ logging: false
+})
+
+export const defaultDatabase = createDatabase(sequelize)
+export const defaultUmzug = createUmzug(sequelize)
diff --git a/src/database/migration/migrations/20181014-setup-tables.ts b/src/database/migration/migrations/20181014-setup-tables.ts
index 7804155..d3a1d37 100644
--- a/src/database/migration/migrations/20181014-setup-tables.ts
+++ b/src/database/migration/migrations/20181014-setup-tables.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -18,11 +18,11 @@
import { QueryInterface, Sequelize, Transaction } from 'sequelize'
import { attributes as addDeviceTokenAttributes } from '../../adddevicetoken'
import { attributes as appAttributes } from '../../app'
-import { attributes as authTokenAttributes } from '../../authtoken'
+import { attributesVersion1 as authTokenAttributes } from '../../authtoken'
import { attributesVersion1 as categoryAttributes } from '../../category'
import { attributes as categoryAppAttributes } from '../../categoryapp'
import { attributesVersion1 as deviceAttributes } from '../../device'
-import { attributes as familyAttributes } from '../../family'
+import { attributesVersion1 as familyAttributes } from '../../family'
import { attributes as purchaseAttributes } from '../../purchase'
import { attributesVersion1 as timelimitruleAttributes } from '../../timelimitrule'
import { attributesVersion1 as usedTimeAttribute } from '../../usedtime'
diff --git a/src/database/migration/migrations/20190113-mail-login-tokens.ts b/src/database/migration/migrations/20190113-mail-login-tokens.ts
index 0f122ab..0c40ae9 100644
--- a/src/database/migration/migrations/20190113-mail-login-tokens.ts
+++ b/src/database/migration/migrations/20190113-mail-login-tokens.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,7 +16,7 @@
*/
import { QueryInterface, Sequelize, Transaction } from 'sequelize'
-import { attributes as mailLoginTokenAttributes } from '../../maillogintoken'
+import { attributesVersion1 as mailLoginTokenAttributes } from '../../maillogintoken'
export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
await sequelize.transaction({
diff --git a/src/database/migration/migrations/20200525-add-new-limit-options.ts b/src/database/migration/migrations/20200525-add-new-limit-options.ts
index ce05f2a..eda4a98 100644
--- a/src/database/migration/migrations/20200525-add-new-limit-options.ts
+++ b/src/database/migration/migrations/20200525-add-new-limit-options.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -58,12 +58,24 @@ export async function up (queryInterface: QueryInterface, sequelize: Sequelize)
...usedTimeAttributesVersion3
}, { transaction })
- await sequelize.query(`
- INSERT INTO UsedTimes (familyId, categoryId, dayOfEpoch, usedTime, lastUpdate, startMinuteOfDay, endMinuteOfDay)
- SELECT familyId, categoryId, dayOfEpoch, usedTime, lastUpdate,
- ${MinuteOfDay.MIN} AS startMinuteOfDay, ${MinuteOfDay.MAX} AS endMinuteOfDay
- FROM UsedTimesOld
- `, { transaction })
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+
+ if (isMysql) {
+ await sequelize.query(`
+ INSERT INTO UsedTimes (familyId, categoryId, dayOfEpoch, usedTime, lastUpdate, startMinuteOfDay, endMinuteOfDay)
+ SELECT familyId, categoryId, dayOfEpoch, usedTime, lastUpdate,
+ ${MinuteOfDay.MIN} AS startMinuteOfDay, ${MinuteOfDay.MAX} AS endMinuteOfDay
+ FROM UsedTimesOld
+ `, { transaction })
+ } else {
+ await sequelize.query(`
+ INSERT INTO "UsedTimes" ("familyId", "categoryId", "dayOfEpoch", "usedTime", "lastUpdate", "startMinuteOfDay", "endMinuteOfDay")
+ SELECT "familyId", "categoryId", "dayOfEpoch", "usedTime", "lastUpdate",
+ ${MinuteOfDay.MIN} AS "startMinuteOfDay", ${MinuteOfDay.MAX} AS "endMinuteOfDay"
+ FROM "UsedTimesOld"
+ `, { transaction })
+ }
await queryInterface.dropTable('UsedTimesOld', { transaction })
})
diff --git a/src/database/migration/migrations/20200601-fix-purchase-table.ts b/src/database/migration/migrations/20200601-fix-purchase-table.ts
index 65dc2ae..abb2410 100644
--- a/src/database/migration/migrations/20200601-fix-purchase-table.ts
+++ b/src/database/migration/migrations/20200601-fix-purchase-table.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -25,11 +25,22 @@ export async function up (queryInterface: QueryInterface, sequelize: Sequelize)
await queryInterface.renameTable('Purchases', 'PurchasesOld', { transaction })
await queryInterface.createTable('Purchases', purchaseAttributes, { transaction })
- await sequelize.query(`
- INSERT INTO Purchases (familyId, service, transactionId, type, loggedAt, previousFullVersionEndTime, newFullVersionEndTime)
- SELECT familyId, service, transactionId, type, 0 AS loggedAt, 0 AS previousFullVersionEndTime, loggedAt AS newFullVersionEndTime
- FROM PurchasesOld
- `, { transaction })
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+
+ if (isMysql) {
+ await sequelize.query(`
+ INSERT INTO Purchases (familyId, service, transactionId, type, loggedAt, previousFullVersionEndTime, newFullVersionEndTime)
+ SELECT familyId, service, transactionId, type, 0 AS loggedAt, 0 AS previousFullVersionEndTime, loggedAt AS newFullVersionEndTime
+ FROM PurchasesOld
+ `, { transaction })
+ } else {
+ await sequelize.query(`
+ INSERT INTO "Purchases" ("familyId", service, "transactionId", type, "loggedAt", "previousFullVersionEndTime", "newFullVersionEndTime")
+ SELECT "familyId", service, "transactionId", type, 0 AS "loggedAt", 0 AS "previousFullVersionEndTime", "loggedAt" AS "newFullVersionEndTime"
+ FROM "PurchasesOld"
+ `, { transaction })
+ }
await queryInterface.dropTable('PurchasesOld', { transaction })
})
diff --git a/src/database/migration/migrations/20200706-create-user-limit-login-category-table.ts b/src/database/migration/migrations/20200706-create-user-limit-login-category-table.ts
index 55d9740..a8b9d35 100644
--- a/src/database/migration/migrations/20200706-create-user-limit-login-category-table.ts
+++ b/src/database/migration/migrations/20200706-create-user-limit-login-category-table.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -21,14 +21,28 @@ export async function up (queryInterface: QueryInterface, sequelize: Sequelize)
await sequelize.transaction({
type: Transaction.TYPES.EXCLUSIVE
}, async (transaction) => {
- await sequelize.query(
- 'CREATE TABLE `UserLimitLoginCategories`' +
- '(`familyId` VARCHAR(10) NOT NULL, `userId` VARCHAR(6) NOT NULL, `categoryId` VARCHAR(6) NOT NULL,' +
- 'PRIMARY KEY(`familyId`, `userId`), FOREIGN KEY(`familyId`, `userId`) REFERENCES `Users`(`familyId`, `userId`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`familyId`, `categoryId`) REFERENCES `Categories`(`familyId`, `categoryId`) ON UPDATE CASCADE ON DELETE CASCADE )',
- { transaction }
- )
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
- await sequelize.query('CREATE INDEX `UserLimitLoginCategoriesIndexCategoryId` ON `UserLimitLoginCategories` (`familyId`, `categoryId`)', { transaction })
+ if (isMysql) {
+ await sequelize.query(
+ 'CREATE TABLE `UserLimitLoginCategories`' +
+ '(`familyId` VARCHAR(10) NOT NULL, `userId` VARCHAR(6) NOT NULL, `categoryId` VARCHAR(6) NOT NULL,' +
+ 'PRIMARY KEY(`familyId`, `userId`), FOREIGN KEY(`familyId`, `userId`) REFERENCES `Users`(`familyId`, `userId`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`familyId`, `categoryId`) REFERENCES `Categories`(`familyId`, `categoryId`) ON UPDATE CASCADE ON DELETE CASCADE )',
+ { transaction }
+ )
+
+ await sequelize.query('CREATE INDEX `UserLimitLoginCategoriesIndexCategoryId` ON `UserLimitLoginCategories` (`familyId`, `categoryId`)', { transaction })
+ } else {
+ await sequelize.query(
+ 'CREATE TABLE "UserLimitLoginCategories"' +
+ '("familyId" VARCHAR(10) NOT NULL, "userId" VARCHAR(6) NOT NULL, "categoryId" VARCHAR(6) NOT NULL,' +
+ 'PRIMARY KEY("familyId", "userId"), FOREIGN KEY("familyId", "userId") REFERENCES "Users" ("familyId", "userId") ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY("familyId", "categoryId") REFERENCES "Categories" ("familyId", "categoryId") ON UPDATE CASCADE ON DELETE CASCADE )',
+ { transaction }
+ )
+
+ await sequelize.query('CREATE INDEX "UserLimitLoginCategoriesIndexCategoryId" ON "UserLimitLoginCategories" ("familyId", "categoryId")', { transaction })
+ }
})
}
diff --git a/src/database/migration/migrations/20200824-create-category-network-id-table.ts b/src/database/migration/migrations/20200824-create-category-network-id-table.ts
index 720adee..54dd7b5 100644
--- a/src/database/migration/migrations/20200824-create-category-network-id-table.ts
+++ b/src/database/migration/migrations/20200824-create-category-network-id-table.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -21,14 +21,28 @@ export async function up (_: QueryInterface, sequelize: Sequelize) {
await sequelize.transaction({
type: Transaction.TYPES.EXCLUSIVE
}, async (transaction) => {
- await sequelize.query(
- 'CREATE TABLE `CategoryNetworkIds` ' +
- '(`familyId` VARCHAR(10) NOT NULL, `categoryId` VARCHAR(6) NOT NULL,' +
- '`networkItemId` VARCHAR(6) NOT NULL, `hashedNetworkId` VARCHAR(8) NOT NULL,' +
- 'PRIMARY KEY(`familyId`, `categoryId`, `networkItemId`), FOREIGN KEY(`familyId`, `categoryId`)' +
- 'REFERENCES `Categories`(`familyId`, `categoryId`) ON UPDATE CASCADE ON DELETE CASCADE )',
- { transaction }
- )
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+
+ if (isMysql) {
+ await sequelize.query(
+ 'CREATE TABLE `CategoryNetworkIds` ' +
+ '(`familyId` VARCHAR(10) NOT NULL, `categoryId` VARCHAR(6) NOT NULL,' +
+ '`networkItemId` VARCHAR(6) NOT NULL, `hashedNetworkId` VARCHAR(8) NOT NULL,' +
+ 'PRIMARY KEY(`familyId`, `categoryId`, `networkItemId`), FOREIGN KEY(`familyId`, `categoryId`)' +
+ 'REFERENCES `Categories`(`familyId`, `categoryId`) ON UPDATE CASCADE ON DELETE CASCADE )',
+ { transaction }
+ )
+ } else {
+ await sequelize.query(
+ 'CREATE TABLE "CategoryNetworkIds" ' +
+ '("familyId" VARCHAR(10) NOT NULL, "categoryId" VARCHAR(6) NOT NULL,' +
+ '"networkItemId" VARCHAR(6) NOT NULL, "hashedNetworkId" VARCHAR(8) NOT NULL,' +
+ 'PRIMARY KEY("familyId", "categoryId", "networkItemId"), FOREIGN KEY("familyId", "categoryId")' +
+ 'REFERENCES "Categories"("familyId", "categoryId") ON UPDATE CASCADE ON DELETE CASCADE )',
+ { transaction }
+ )
+ }
})
}
diff --git a/src/database/migration/migrations/20201116-add-child-tasks.ts b/src/database/migration/migrations/20201116-add-child-tasks.ts
index bcf4223..117a3d0 100644
--- a/src/database/migration/migrations/20201116-add-child-tasks.ts
+++ b/src/database/migration/migrations/20201116-add-child-tasks.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -22,18 +22,36 @@ export async function up (queryInterface: QueryInterface, sequelize: Sequelize)
await sequelize.transaction({
type: Transaction.TYPES.EXCLUSIVE
}, async (transaction) => {
- await sequelize.query(
- 'CREATE TABLE `ChildTasks` (' +
- '`familyId` VARCHAR(10) NOT NULL, `taskId` VARCHAR(6) NOT NULL,' +
- '`categoryId` VARCHAR(6) NOT NULL, `taskTitle` VARCHAR(50) NOT NULL,' +
- '`extraTimeDuration` INTEGER NOT NULL, `pendingRequest` INTEGER NOT NULL,' +
- '`lastGrantTimestamp` LONG NOT NULL,' +
- 'PRIMARY KEY(`familyId`, `taskId`),' +
- 'FOREIGN KEY(`familyId`, `categoryId`) REFERENCES `Categories`(`familyId`, `categoryId`) ' +
- 'ON UPDATE CASCADE ON DELETE CASCADE' +
- ')',
- { transaction }
- )
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+
+ if (isMysql) {
+ await sequelize.query(
+ 'CREATE TABLE `ChildTasks` (' +
+ '`familyId` VARCHAR(10) NOT NULL, `taskId` VARCHAR(6) NOT NULL,' +
+ '`categoryId` VARCHAR(6) NOT NULL, `taskTitle` VARCHAR(50) NOT NULL,' +
+ '`extraTimeDuration` INTEGER NOT NULL, `pendingRequest` INTEGER NOT NULL,' +
+ '`lastGrantTimestamp` LONG NOT NULL,' +
+ 'PRIMARY KEY(`familyId`, `taskId`),' +
+ 'FOREIGN KEY(`familyId`, `categoryId`) REFERENCES `Categories`(`familyId`, `categoryId`) ' +
+ 'ON UPDATE CASCADE ON DELETE CASCADE' +
+ ')',
+ { transaction }
+ )
+ } else {
+ await sequelize.query(
+ 'CREATE TABLE "ChildTasks" (' +
+ '"familyId" VARCHAR(10) NOT NULL, "taskId" VARCHAR(6) NOT NULL,' +
+ '"categoryId" VARCHAR(6) NOT NULL, "taskTitle" VARCHAR(50) NOT NULL,' +
+ '"extraTimeDuration" INTEGER NOT NULL, "pendingRequest" INTEGER NOT NULL,' +
+ '"lastGrantTimestamp" BIGINT NOT NULL,' +
+ 'PRIMARY KEY("familyId", "taskId"),' +
+ 'FOREIGN KEY("familyId", "categoryId") REFERENCES "Categories"("familyId", "categoryId") ' +
+ 'ON UPDATE CASCADE ON DELETE CASCADE' +
+ ')',
+ { transaction }
+ )
+ }
await queryInterface.addColumn('Categories', 'taskListVersion', {
...categoryAttributes.taskListVersion
diff --git a/src/database/migration/migrations/20201123-add-per-day-rules.ts b/src/database/migration/migrations/20201123-add-per-day-rules.ts
new file mode 100644
index 0000000..44f26bb
--- /dev/null
+++ b/src/database/migration/migrations/20201123-add-per-day-rules.ts
@@ -0,0 +1,38 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2020 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion3 as ruleAttributes } from '../../timelimitrule'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ // timelimit rule table
+ await queryInterface.addColumn('TimelimitRules', 'perDay', {
+ ...ruleAttributes.perDay
+ }, { transaction })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('TimelimitRules', 'perDay', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20201228-add-pre-block.ts b/src/database/migration/migrations/20201228-add-pre-block.ts
new file mode 100644
index 0000000..0a5485a
--- /dev/null
+++ b/src/database/migration/migrations/20201228-add-pre-block.ts
@@ -0,0 +1,38 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2020 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion2 as limitLoginCategoryAttributes } from '../../userlimitlogincategory'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ // timelimit rule table
+ await queryInterface.addColumn('UserLimitLoginCategories', 'preBlockDuration', {
+ ...limitLoginCategoryAttributes.preBlockDuration
+ }, { transaction })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('UserLimitLoginCategories', 'preBlockDuration', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20210125-add-category-flags.ts b/src/database/migration/migrations/20210125-add-category-flags.ts
new file mode 100644
index 0000000..87f8aa7
--- /dev/null
+++ b/src/database/migration/migrations/20210125-add-category-flags.ts
@@ -0,0 +1,39 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion11 as categoryAttributes } from '../../category'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.addColumn('Categories', 'flags', {
+ ...categoryAttributes.flags
+ }, {
+ transaction
+ })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('Categories', 'flags', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20211213-add-notification-block-delay.ts b/src/database/migration/migrations/20211213-add-notification-block-delay.ts
new file mode 100644
index 0000000..5c5c295
--- /dev/null
+++ b/src/database/migration/migrations/20211213-add-notification-block-delay.ts
@@ -0,0 +1,39 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion12 as categoryAttributes } from '../../category'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.addColumn('Categories', 'blockNotificationDelay', {
+ ...categoryAttributes.blockNotificationDelay
+ }, {
+ transaction
+ })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('Categories', 'blockNotificationDelay', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20213027-add-login-process-locale-storage.ts b/src/database/migration/migrations/20213027-add-login-process-locale-storage.ts
new file mode 100644
index 0000000..35951e7
--- /dev/null
+++ b/src/database/migration/migrations/20213027-add-login-process-locale-storage.ts
@@ -0,0 +1,47 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion2 as authTokenAttributes } from '../../authtoken'
+import { attributesVersion2 as mailLoginTokenAttributes } from '../../maillogintoken'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.addColumn('AuthTokens', 'locale', {
+ ...authTokenAttributes.locale
+ }, {
+ transaction
+ })
+
+ await queryInterface.addColumn('MailLoginTokens', 'locale', {
+ ...mailLoginTokenAttributes.locale
+ }, {
+ transaction
+ })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('AuthTokens', 'locale', { transaction })
+ await queryInterface.removeColumn('MailLoginTokens', 'locale', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220328-add-custom-time-limits.ts b/src/database/migration/migrations/20220328-add-custom-time-limits.ts
new file mode 100644
index 0000000..cec7198
--- /dev/null
+++ b/src/database/migration/migrations/20220328-add-custom-time-limits.ts
@@ -0,0 +1,55 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+
+export async function up (_: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+
+ if (isMysql) {
+ await sequelize.query(
+ 'CREATE TABLE `CategoryTimeWarnings` ' +
+ '(`familyId` VARCHAR(10) NOT NULL, `categoryId` VARCHAR(6) NOT NULL,' +
+ '`minutes` INTEGER NOT NULL, ' +
+ 'PRIMARY KEY(`familyId`, `categoryId`, `minutes`), FOREIGN KEY(`familyId`, `categoryId`)' +
+ 'REFERENCES `Categories`(`familyId`, `categoryId`) ON UPDATE CASCADE ON DELETE CASCADE )',
+ { transaction }
+ )
+ } else {
+ await sequelize.query(
+ 'CREATE TABLE "CategoryTimeWarnings" ' +
+ '("familyId" VARCHAR(10) NOT NULL, "categoryId" VARCHAR(6) NOT NULL,' +
+ '"minutes" INTEGER NOT NULL, ' +
+ 'PRIMARY KEY("familyId", "categoryId", "minutes"), FOREIGN KEY("familyId", "categoryId")' +
+ 'REFERENCES "Categories"("familyId", "categoryId") ON UPDATE CASCADE ON DELETE CASCADE )',
+ { transaction }
+ )
+ }
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.dropTable('CategoryTimeWarnings', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220711-add-manipulation-flags.ts b/src/database/migration/migrations/20220711-add-manipulation-flags.ts
new file mode 100644
index 0000000..0f892bc
--- /dev/null
+++ b/src/database/migration/migrations/20220711-add-manipulation-flags.ts
@@ -0,0 +1,39 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion12 as deviceAttributes } from '../../device'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.addColumn('Devices', 'manipulationFlags', {
+ ...deviceAttributes.manipulationFlags
+ }, {
+ transaction
+ })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('Devices', 'manipulationFlags', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220725-create-encrypted-app-lists.ts b/src/database/migration/migrations/20220725-create-encrypted-app-lists.ts
new file mode 100644
index 0000000..273a028
--- /dev/null
+++ b/src/database/migration/migrations/20220725-create-encrypted-app-lists.ts
@@ -0,0 +1,62 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+ const isPosgresql = dialect === 'postgres'
+
+ if (isMysql) {
+ await sequelize.query(
+ 'CREATE TABLE `EncryptedAppLists` ' +
+ '(`familyId` VARCHAR(10) NOT NULL, `deviceId` VARCHAR(6) NOT NULL,' +
+ '`type` INTEGER NOT NULL, `version` VARCHAR(4) NOT NULL,' +
+ '`data` BLOB NOT NULL, ' +
+ 'PRIMARY KEY (`familyId`, `deviceId`, `type`),' +
+ 'FOREIGN KEY (`familyId`, `deviceId`) REFERENCES `Devices` (`familyId`, `deviceId`) ON UPDATE CASCADE ON DELETE CASCADE' +
+ ')',
+ { transaction }
+ )
+ } else {
+ await sequelize.query(
+ 'CREATE TABLE "EncryptedAppLists" ' +
+ '("familyId" VARCHAR(10) NOT NULL, "deviceId" VARCHAR(6) NOT NULL,' +
+ '"type" INTEGER NOT NULL, "version" VARCHAR(4) NOT NULL,' +
+ '"data" ' + (isPosgresql ? 'BYTEA' : 'BLOB') + ' NOT NULL, ' +
+ 'PRIMARY KEY ("familyId", "deviceId", "type"),' +
+ 'FOREIGN KEY ("familyId", "deviceId") REFERENCES "Devices" ("familyId", "deviceId") ON UPDATE CASCADE ON DELETE CASCADE' +
+ ')',
+ { transaction }
+ )
+ }
+
+ await queryInterface.addIndex('EncryptedAppLists', ['familyId', 'deviceId', 'type', 'version'], { transaction })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.dropTable('EncryptedAppLists', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220726-add-device-publickey.ts b/src/database/migration/migrations/20220726-add-device-publickey.ts
new file mode 100644
index 0000000..f7d9c96
--- /dev/null
+++ b/src/database/migration/migrations/20220726-add-device-publickey.ts
@@ -0,0 +1,39 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion13 as deviceAttributes } from '../../device'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.addColumn('Devices', 'publicKey', {
+ ...deviceAttributes.publicKey
+ }, {
+ transaction
+ })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('Devices', 'publicKey', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220727-add-family-requestseq.ts b/src/database/migration/migrations/20220727-add-family-requestseq.ts
new file mode 100644
index 0000000..cd3f809
--- /dev/null
+++ b/src/database/migration/migrations/20220727-add-family-requestseq.ts
@@ -0,0 +1,39 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion2 as familyAttributes } from '../../family'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.addColumn('Families', 'nextServerKeyRequestSeq', {
+ ...familyAttributes.nextServerKeyRequestSeq
+ }, {
+ transaction
+ })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('Families', 'nextServerKeyRequestSeq', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220728-create-key-requests.ts b/src/database/migration/migrations/20220728-create-key-requests.ts
new file mode 100644
index 0000000..4fc4585
--- /dev/null
+++ b/src/database/migration/migrations/20220728-create-key-requests.ts
@@ -0,0 +1,81 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+ const isPosgresql = dialect === 'postgres'
+
+ if (isMysql) {
+ await sequelize.query(
+ 'CREATE TABLE `KeyRequests` (' +
+ '`familyId` VARCHAR(10) NOT NULL, ' +
+ '`serverSequenceNumber` BIGINT NOT NULL, ' +
+ '`senderDeviceId` VARCHAR(6) NOT NULL, ' +
+ '`senderSequenceNumber` BIGINT NOT NULL, ' +
+ '`deviceId` VARCHAR(6) NULL, ' +
+ '`categoryId` VARCHAR(6) NULL, ' +
+ '`type` INTEGER NOT NULL, ' +
+ '`tempKey` BLOB NOT NULL, ' +
+ '`signature` BLOB NOT NULL, ' +
+ 'PRIMARY KEY (`familyId`, `serverSequenceNumber`), ' +
+ 'FOREIGN KEY (`familyId`, `senderDeviceId`) REFERENCES `Devices` (`familyId`, `deviceId`) ON UPDATE CASCADE ON DELETE CASCADE, ' +
+ 'FOREIGN KEY (`familyId`, `deviceId`) REFERENCES `Devices` (`familyId`, `deviceId`) ON UPDATE CASCADE ON DELETE CASCADE, ' +
+ 'FOREIGN KEY (`familyId`, `categoryId`) REFERENCES `Categories` (`familyId`, `categoryId`) ON UPDATE CASCADE ON DELETE CASCADE' +
+ ')',
+ { transaction }
+ )
+ } else {
+ await sequelize.query(
+ 'CREATE TABLE "KeyRequests" (' +
+ '"familyId" VARCHAR(10) NOT NULL, ' +
+ '"serverSequenceNumber" ' + (isPosgresql ? 'BIGINT' : 'LONG') + ' NOT NULL, ' +
+ '"senderDeviceId" VARCHAR(6) NOT NULL, ' +
+ '"senderSequenceNumber" ' + (isPosgresql ? 'BIGINT' : 'LONG') + ' NOT NULL, ' +
+ '"deviceId" VARCHAR(6) NULL, ' +
+ '"categoryId" VARCHAR(6) NULL, ' +
+ '"type" INTEGER NOT NULL, ' +
+ '"tempKey" ' + (isPosgresql ? 'BYTEA' : 'BLOB') + ' NOT NULL, ' +
+ '"signature" ' + (isPosgresql ? 'BYTEA' : 'BLOB') + ' NOT NULL, ' +
+ 'PRIMARY KEY ("familyId", "serverSequenceNumber"), ' +
+ 'FOREIGN KEY ("familyId", "senderDeviceId") REFERENCES "Devices" ("familyId", "deviceId") ON UPDATE CASCADE ON DELETE CASCADE, ' +
+ 'FOREIGN KEY ("familyId", "deviceId") REFERENCES "Devices" ("familyId", "deviceId") ON UPDATE CASCADE ON DELETE CASCADE, ' +
+ 'FOREIGN KEY ("familyId", "categoryId") REFERENCES "Categories" ("familyId", "categoryId") ON UPDATE CASCADE ON DELETE CASCADE' +
+ ')',
+ { transaction }
+ )
+ }
+
+ await queryInterface.addIndex('KeyRequests', ['familyId', 'senderDeviceId', 'senderSequenceNumber'], { transaction })
+ await queryInterface.addIndex('KeyRequests', ['familyId', 'deviceId'], { transaction })
+ await queryInterface.addIndex('KeyRequests', ['familyId', 'categoryId'], { transaction })
+ await queryInterface.addIndex('KeyRequests', ['familyId', 'senderDeviceId', 'deviceId', 'categoryId'], { transaction, unique: true })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.dropTable('KeyRequests', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220729-create-key-responses.ts b/src/database/migration/migrations/20220729-create-key-responses.ts
new file mode 100644
index 0000000..29becd1
--- /dev/null
+++ b/src/database/migration/migrations/20220729-create-key-responses.ts
@@ -0,0 +1,83 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+ const isPosgresql = dialect === 'postgres'
+
+ if (isMysql) {
+ await sequelize.query(
+ 'CREATE TABLE `KeyResponses` (' +
+ '`familyId` VARCHAR(10) NOT NULL, ' +
+ '`receiverDeviceId` VARCHAR(6) NOT NULL, ' +
+ '`requestServerSequenceNumber` BIGINT NOT NULL, ' +
+ '`senderDeviceId` VARCHAR(6) NOT NULL, ' +
+ '`replyServerSequenceNumber` BIGINT NOT NULL, ' +
+ '`requestClientSequenceNumber` BIGINT NOT NULL, ' +
+ '`tempKey` BLOB NOT NULL, ' +
+ '`encryptedKey` BLOB NOT NULL, ' +
+ '`signature` BLOB NOT NULL, ' +
+ 'PRIMARY KEY (`familyId`, `receiverDeviceId`, `requestServerSequenceNumber`, `senderDeviceId`), ' +
+ 'FOREIGN KEY (`familyId`, `requestServerSequenceNumber`) REFERENCES `KeyRequests` (`familyId`, `serverSequenceNumber`) ON UPDATE CASCADE ON DELETE CASCADE ' +
+ ')',
+ { transaction }
+ )
+ } else {
+ await sequelize.query(
+ 'CREATE TABLE "KeyResponses" (' +
+ '"familyId" VARCHAR(10) NOT NULL, ' +
+ '"receiverDeviceId" VARCHAR(6) NOT NULL, ' +
+ '"requestServerSequenceNumber" ' + (isPosgresql ? 'BIGINT' : 'LONG') + ' NOT NULL, ' +
+ '"senderDeviceId" VARCHAR(6) NOT NULL, ' +
+ '"replyServerSequenceNumber" ' + (isPosgresql ? 'BIGINT' : 'LONG') + ' NOT NULL, ' +
+ '"requestClientSequenceNumber" ' + (isPosgresql ? 'BIGINT' : 'LONG') + ' NOT NULL, ' +
+ '"tempKey" ' + (isPosgresql ? 'BYTEA' : 'BLOB') + ' NOT NULL, ' +
+ '"encryptedKey" ' + (isPosgresql ? 'BYTEA' : 'BLOB') + ' NOT NULL, ' +
+ '"signature" ' + (isPosgresql ? 'BYTEA' : 'BLOB') + ' NOT NULL, ' +
+ 'PRIMARY KEY ("familyId", "receiverDeviceId", "requestServerSequenceNumber", "senderDeviceId"), ' +
+ 'FOREIGN KEY ("familyId", "requestServerSequenceNumber") REFERENCES "KeyRequests" ("familyId", "serverSequenceNumber") ON UPDATE CASCADE ON DELETE CASCADE ' +
+ ')',
+ { transaction }
+ )
+ }
+
+ await queryInterface.addIndex('KeyResponses', ['familyId', 'requestServerSequenceNumber'], { transaction })
+ await queryInterface.addIndex(
+ 'KeyResponses',
+ ['familyId', 'receiverDeviceId', 'replyServerSequenceNumber'],
+ {
+ transaction,
+ unique: true,
+ name: 'key_response_index_fid_rdid_rssn'
+ }
+ )
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.dropTable('KeyResponses', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220730-add-device-key-response-counter.ts b/src/database/migration/migrations/20220730-add-device-key-response-counter.ts
new file mode 100644
index 0000000..2849d4f
--- /dev/null
+++ b/src/database/migration/migrations/20220730-add-device-key-response-counter.ts
@@ -0,0 +1,39 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion14 as deviceAttributes } from '../../device'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.addColumn('Devices', 'nextKeyReplySequenceNumber', {
+ ...deviceAttributes.nextKeyReplySequenceNumber
+ }, {
+ transaction
+ })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('Devices', 'nextKeyReplySequenceNumber', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220912-encrypted-applist-mysql-mediumblob.ts b/src/database/migration/migrations/20220912-encrypted-applist-mysql-mediumblob.ts
new file mode 100644
index 0000000..da60396
--- /dev/null
+++ b/src/database/migration/migrations/20220912-encrypted-applist-mysql-mediumblob.ts
@@ -0,0 +1,50 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+
+ if (isMysql) {
+ await sequelize.query(
+ 'ALTER TABLE `EncryptedAppLists` MODIFY `data` MEDIUMBLOB',
+ { transaction }
+ )
+ }
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+
+ if (isMysql) {
+ await sequelize.query(
+ 'ALTER TABLE `EncryptedAppLists` MODIFY `data` BLOB',
+ { transaction }
+ )
+ }
+ })
+}
diff --git a/src/database/migration/migrations/20220913-create-device-dh-keys.ts b/src/database/migration/migrations/20220913-create-device-dh-keys.ts
new file mode 100644
index 0000000..0929d3d
--- /dev/null
+++ b/src/database/migration/migrations/20220913-create-device-dh-keys.ts
@@ -0,0 +1,70 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+ const isPosgresql = dialect === 'postgres'
+
+ if (isMysql) {
+ await sequelize.query(
+ 'CREATE TABLE `DeviceDhKeys` ' +
+ '(`familyId` VARCHAR(10) NOT NULL,' +
+ '`deviceId` VARCHAR(6) NOT NULL,' +
+ '`version` VARCHAR(4) NOT NULL,' +
+ '`createdAt` BIGINT NOT NULL, ' +
+ '`expireAt` BIGINT NULL, ' +
+ '`publicKey` BLOB NOT NULL, ' +
+ '`privateKey` BLOB NOT NULL, ' +
+ 'PRIMARY KEY (`familyId`, `deviceId`, `version`),' +
+ 'FOREIGN KEY (`familyId`, `deviceId`) REFERENCES `Devices` (`familyId`, `deviceId`) ON UPDATE CASCADE ON DELETE CASCADE' +
+ ')',
+ { transaction }
+ )
+ } else {
+ await sequelize.query(
+ 'CREATE TABLE "DeviceDhKeys" ' +
+ '("familyId" VARCHAR(10) NOT NULL,' +
+ '"deviceId" VARCHAR(6) NOT NULL,' +
+ '"version" VARCHAR(4) NOT NULL,' +
+ '"createdAt" ' + (isPosgresql ? 'BIGINT' : 'LONG') + ' NOT NULL, ' +
+ '"expireAt" ' + (isPosgresql ? 'BIGINT' : 'LONG') + ' NULL, ' +
+ '"publicKey" ' + (isPosgresql ? 'BYTEA' : 'BLOB') + ' NOT NULL, ' +
+ '"privateKey" ' + (isPosgresql ? 'BYTEA' : 'BLOB') + ' NOT NULL, ' +
+ 'PRIMARY KEY ("familyId", "deviceId", "version"),' +
+ 'FOREIGN KEY ("familyId", "deviceId") REFERENCES "Devices" ("familyId", "deviceId") ON UPDATE CASCADE ON DELETE CASCADE' +
+ ')',
+ { transaction }
+ )
+ }
+
+ await queryInterface.addIndex('DeviceDhKeys', ['expireAt'], { transaction })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.dropTable('DeviceDhKeys', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220919-create-u2f-keys.ts b/src/database/migration/migrations/20220919-create-u2f-keys.ts
new file mode 100644
index 0000000..a7fb06a
--- /dev/null
+++ b/src/database/migration/migrations/20220919-create-u2f-keys.ts
@@ -0,0 +1,70 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ const dialect = sequelize.getDialect()
+ const isMysql = dialect === 'mysql' || dialect === 'mariadb'
+ const isPosgresql = dialect === 'postgres'
+
+ if (isMysql) {
+ await sequelize.query(
+ 'CREATE TABLE `U2fKeys` ' +
+ '(`familyId` VARCHAR(10) NOT NULL,' +
+ '`keyId` VARCHAR(8) NOT NULL,' +
+ '`userId` VARCHAR(6) NOT NULL,' +
+ '`addedAt` BIGINT NOT NULL, ' +
+ '`keyHandle` BLOB NOT NULL, ' +
+ '`publicKey` BLOB NOT NULL, ' +
+ '`nextCounter` BIGINT NOT NULL, ' +
+ 'PRIMARY KEY (`familyId`, `keyId`),' +
+ 'FOREIGN KEY (`familyId`, `userId`) REFERENCES `Users` (`familyId`, `userId`) ON UPDATE CASCADE ON DELETE CASCADE' +
+ ')',
+ { transaction }
+ )
+ } else {
+ await sequelize.query(
+ 'CREATE TABLE "U2fKeys" ' +
+ '("familyId" VARCHAR(10) NOT NULL,' +
+ '"keyId" VARCHAR(8) NOT NULL,' +
+ '"userId" VARCHAR(6) NOT NULL,' +
+ '"addedAt" ' + (isPosgresql ? 'BIGINT' : 'LONG') + ' NOT NULL, ' +
+ '"keyHandle" ' + (isPosgresql ? 'BYTEA' : 'BLOB') + ' NOT NULL, ' +
+ '"publicKey" ' + (isPosgresql ? 'BYTEA' : 'BLOB') + ' NOT NULL, ' +
+ '"nextCounter" ' + (isPosgresql ? 'BIGINT' : 'LONG') + ' NOT NULL, ' +
+ 'PRIMARY KEY ("familyId", "keyId"),' +
+ 'FOREIGN KEY ("familyId", "userId") REFERENCES "Users" ("familyId", "userId") ON UPDATE CASCADE ON DELETE CASCADE' +
+ ')',
+ { transaction }
+ )
+ }
+
+ await queryInterface.addIndex('U2fKeys', ['familyId', 'userId'], { transaction })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.dropTable('U2fKeys', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220920-add-family-u2f-version.ts b/src/database/migration/migrations/20220920-add-family-u2f-version.ts
new file mode 100644
index 0000000..43859c0
--- /dev/null
+++ b/src/database/migration/migrations/20220920-add-family-u2f-version.ts
@@ -0,0 +1,39 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion3 as familyAttributes } from '../../family'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.addColumn('Families', 'u2fKeysVersion', {
+ ...familyAttributes.u2fKeysVersion
+ }, {
+ transaction
+ })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('Families', 'u2fKeysVersion', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20220921-add-dh-subsequence.ts b/src/database/migration/migrations/20220921-add-dh-subsequence.ts
new file mode 100644
index 0000000..7157cd5
--- /dev/null
+++ b/src/database/migration/migrations/20220921-add-dh-subsequence.ts
@@ -0,0 +1,39 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion2 as dhKeyAttributes } from '../../devicedhkey'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.addColumn('DeviceDhKeys', 'createdAtSubsequence', {
+ ...dhKeyAttributes.createdAtSubsequence
+ }, {
+ transaction
+ })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('DeviceDhKeys', 'createdAtSubsequence', { transaction })
+ })
+}
diff --git a/src/database/migration/migrations/20221114-remove-apps-and-activities.ts b/src/database/migration/migrations/20221114-remove-apps-and-activities.ts
new file mode 100644
index 0000000..56ac13b
--- /dev/null
+++ b/src/database/migration/migrations/20221114-remove-apps-and-activities.ts
@@ -0,0 +1,31 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.dropTable('Apps', { transaction })
+ await queryInterface.dropTable('AppActivities', { transaction })
+ })
+}
+
+export async function down() {
+ throw new Error('not possible')
+}
diff --git a/src/database/migration/migrations/20230612-add-platform-level.ts b/src/database/migration/migrations/20230612-add-platform-level.ts
new file mode 100644
index 0000000..d614544
--- /dev/null
+++ b/src/database/migration/migrations/20230612-add-platform-level.ts
@@ -0,0 +1,46 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { QueryInterface, Sequelize, Transaction } from 'sequelize'
+import { attributesVersion15 as deviceAttributes } from '../../device'
+
+export async function up (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.addColumn('Devices', 'platformType', {
+ ...deviceAttributes.platformType
+ }, {
+ transaction
+ })
+
+ await queryInterface.addColumn('Devices', 'platformLevel', {
+ ...deviceAttributes.platformLevel
+ }, {
+ transaction
+ })
+ })
+}
+
+export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
+ await sequelize.transaction({
+ type: Transaction.TYPES.EXCLUSIVE
+ }, async (transaction) => {
+ await queryInterface.removeColumn('Devices', 'platformLevel', { transaction })
+ await queryInterface.removeColumn('Devices', 'platformType', { transaction })
+ })
+}
diff --git a/src/database/migration/umzug.ts b/src/database/migration/umzug.ts
index 05febc4..7f4f3c4 100644
--- a/src/database/migration/umzug.ts
+++ b/src/database/migration/umzug.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2024 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -17,18 +17,26 @@
import { resolve } from 'path'
import { Sequelize } from 'sequelize'
-import * as Umzug from 'umzug'
+import { Umzug, SequelizeStorage } from 'umzug'
export const createUmzug = (sequelize: Sequelize) => (
new Umzug({
- storage: 'sequelize',
- storageOptions: {
- sequelize
- },
+ storage: new SequelizeStorage({ sequelize }),
migrations: {
- params: [sequelize.getQueryInterface(), sequelize],
- path: resolve(__dirname, '../../../build/database/migration/migrations'),
- pattern: /^\d+[\w-]+\.js$/
- }
+ glob: resolve(__dirname, '../../../build/database/migration/migrations/*.js'),
+ resolve: ({ name, path }) => {
+ if (!path) throw new Error()
+
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
+ const migration = require(path)
+
+ return {
+ name,
+ up: async () => migration.up(sequelize.getQueryInterface(), sequelize),
+ down: async () => migration.down(sequelize.getQueryInterface(), sequelize),
+ }
+ },
+ },
+ logger: console
})
)
diff --git a/src/database/olddevice.ts b/src/database/olddevice.ts
index 3b6d429..90b1c15 100644
--- a/src/database/olddevice.ts
+++ b/src/database/olddevice.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2020 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -23,7 +23,7 @@ export interface OldDeviceAttributes {
deviceAuthToken: string
}
-export type OldDeviceModel = Sequelize.Model & OldDeviceAttributes
+export type OldDeviceModel = Sequelize.Model & OldDeviceAttributes
export type OldDeviceModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): OldDeviceModel;
}
diff --git a/src/database/purchase.ts b/src/database/purchase.ts
index 0b1f35b..e85692d 100644
--- a/src/database/purchase.ts
+++ b/src/database/purchase.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -21,7 +21,7 @@ import { SequelizeAttributes } from './types'
export interface PurchaseAttributes {
familyId: string
- service: 'googleplay'
+ service: 'googleplay' | 'directpurchase'
transactionId: string
type: 'month' | 'year'
loggedAt: string
@@ -29,7 +29,7 @@ export interface PurchaseAttributes {
newFullVersionEndTime: string
}
-export type PurchaseModel = Sequelize.Model & PurchaseAttributes
+export type PurchaseModel = Sequelize.Model & PurchaseAttributes
export type PurchaseModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): PurchaseModel;
}
@@ -37,7 +37,7 @@ export type PurchaseModelStatic = typeof Sequelize.Model & {
export const attributes: SequelizeAttributes = {
familyId: { ...familyIdColumn },
service: {
- ...createEnumColumn(['googleplay']),
+ ...createEnumColumn(['googleplay', 'directpurchase']),
primaryKey: true
},
transactionId: {
diff --git a/src/database/sessionduration.ts b/src/database/sessionduration.ts
index a3ec0c5..9da57bd 100644
--- a/src/database/sessionduration.ts
+++ b/src/database/sessionduration.ts
@@ -36,7 +36,7 @@ interface SessionDurationAttributesVersion1 {
export type SessionDurationAttributes = SessionDurationAttributesVersion1
-export type SessionDurationModel = Sequelize.Model & SessionDurationAttributes
+export type SessionDurationModel = Sequelize.Model & SessionDurationAttributes
export type SessionDurationModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): SessionDurationModel;
}
diff --git a/src/database/timelimitrule.ts b/src/database/timelimitrule.ts
index fe16614..1d0aa1f 100644
--- a/src/database/timelimitrule.ts
+++ b/src/database/timelimitrule.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -37,9 +37,14 @@ interface TimelimitRuleAttributesVersion2 {
sessionPauseMilliseconds: number
}
-type TimelimitRuleAttributes = TimelimitRuleAttributesVersion1 & TimelimitRuleAttributesVersion2
+interface TimelimitRuleAttributesVersion3 {
+ perDay: number
+}
-export type TimelimitRuleModel = Sequelize.Model & TimelimitRuleAttributes
+type TimelimitRuleAttributes = TimelimitRuleAttributesVersion1 &
+ TimelimitRuleAttributesVersion2 & TimelimitRuleAttributesVersion3
+
+export type TimelimitRuleModel = Sequelize.Model & TimelimitRuleAttributes
export type TimelimitRuleModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): TimelimitRuleModel;
}
@@ -56,7 +61,7 @@ export const attributesVersion1: SequelizeAttributes = {
+ perDay: {
+ type: Sequelize.INTEGER,
+ validate: {
+ min: 0,
+ max: 1
+ },
+ allowNull: false,
+ defaultValue: 0
+ }
+}
+
export const attributes: SequelizeAttributes = {
...attributesVersion1,
- ...attributesVersion2
+ ...attributesVersion2,
+ ...attributesVersion3
}
export const createTimelimitRuleModel = (sequelize: Sequelize.Sequelize): TimelimitRuleModelStatic => sequelize.define('TimelimitRule', attributes) as TimelimitRuleModelStatic
diff --git a/src/database/types.ts b/src/database/types.ts
index 13690a1..7097fbc 100644
--- a/src/database/types.ts
+++ b/src/database/types.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -17,6 +17,7 @@
import * as Sequelize from 'sequelize'
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type SequelizeAttributes = {
[P in keyof T]: Sequelize.ModelAttributeColumnOptions;
}
diff --git a/src/database/u2fkey.ts b/src/database/u2fkey.ts
new file mode 100644
index 0000000..83fa04a
--- /dev/null
+++ b/src/database/u2fkey.ts
@@ -0,0 +1,82 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { createHash } from 'crypto'
+import { familyIdColumn, idWithinFamilyColumn, timestampColumn } from './columns'
+import { SequelizeAttributes } from './types'
+import { intToBuffer } from '../util/binary-number'
+
+export function getU2fKeyId({ keyHandle, publicKey }: {
+ keyHandle: Buffer
+ publicKey: Buffer
+}) {
+ return createHash('sha256')
+ .update(intToBuffer(keyHandle.length))
+ .update(keyHandle)
+ .update(intToBuffer(publicKey.length))
+ .update(publicKey)
+ .digest()
+ .slice(0, 6)
+ .toString('base64')
+}
+
+export interface U2fKeyAttributes {
+ familyId: string
+ keyId: string
+ userId: string
+ addedAt: string
+ keyHandle: Buffer
+ publicKey: Buffer
+ nextCounter: string
+}
+
+export type U2fKeyModel = Sequelize.Model & U2fKeyAttributes
+export type U2fKeyModelStatic = typeof Sequelize.Model & {
+ new (values?: object, options?: Sequelize.BuildOptions): U2fKeyModel;
+}
+
+export const attributes: SequelizeAttributes = {
+ familyId: {
+ ...familyIdColumn,
+ primaryKey: true
+ },
+ keyId: {
+ type: Sequelize.STRING(8),
+ primaryKey: true
+ },
+ userId: {
+ ...idWithinFamilyColumn
+ },
+ addedAt: {
+ ...timestampColumn
+ },
+ keyHandle: {
+ type: Sequelize.BLOB,
+ allowNull: false
+ },
+ publicKey: {
+ type: Sequelize.BLOB,
+ allowNull: false
+ },
+ nextCounter: {
+ type: Sequelize.BIGINT,
+ allowNull: false
+ }
+}
+
+export const createU2fKeyModel = (sequelize: Sequelize.Sequelize): U2fKeyModelStatic => sequelize.define('U2fKey', attributes) as U2fKeyModelStatic
diff --git a/src/database/usedtime.ts b/src/database/usedtime.ts
index 4f96169..240a33c 100644
--- a/src/database/usedtime.ts
+++ b/src/database/usedtime.ts
@@ -40,7 +40,7 @@ export interface UsedTimeAttributesVersion3 {
export type UsedTimeAttributes = UsedTimeAttributesVersion1 &
UsedTimeAttributesVersion2 & UsedTimeAttributesVersion3
-export type UsedTimeModel = Sequelize.Model & UsedTimeAttributes
+export type UsedTimeModel = Sequelize.Model & UsedTimeAttributes
export type UsedTimeModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): UsedTimeModel;
}
diff --git a/src/database/user.ts b/src/database/user.ts
index 3d8c83b..4720eec 100644
--- a/src/database/user.ts
+++ b/src/database/user.ts
@@ -22,6 +22,13 @@ import { optionalPasswordRegex, optionalSaltRegex } from '../util/password'
import { booleanColumn, createEnumColumn, familyIdColumn, idWithinFamilyColumn, labelColumn, optionalIdWithinFamilyColumn, timestampColumn } from './columns'
import { SequelizeAttributes } from './types'
+export const maxMailNotificationFlags = 1 | 2
+
+export const mailNotificationFlags = {
+ warnings: 1,
+ tasks: 2
+}
+
export interface UserAttributesVersion1 {
familyId: string
userId: string
@@ -52,6 +59,7 @@ export interface UserAttributesVersion4 {
}
export interface UserAttributesVersion5 {
+ // currently unused
blockedTimes: string
}
@@ -62,7 +70,7 @@ export interface UserAttributesVersion6 {
export type UserAttributes = UserAttributesVersion1 & UserAttributesVersion2 &
UserAttributesVersion3 & UserAttributesVersion4 & UserAttributesVersion5 & UserAttributesVersion6
-export type UserModel = Sequelize.Model & UserAttributes
+export type UserModel = Sequelize.Model & UserAttributes
export type UserModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): UserModel;
}
@@ -128,7 +136,7 @@ export const attributesVersion4: SequelizeAttributes = {
defaultValue: 0,
validate: {
min: 0,
- max: 1
+ max: maxMailNotificationFlags
}
}
}
diff --git a/src/database/userlimitlogincategory.ts b/src/database/userlimitlogincategory.ts
index b7413b3..f82019f 100644
--- a/src/database/userlimitlogincategory.ts
+++ b/src/database/userlimitlogincategory.ts
@@ -19,21 +19,46 @@ import * as Sequelize from 'sequelize'
import { familyIdColumn, idWithinFamilyColumn } from './columns'
import { SequelizeAttributes } from './types'
-export interface UserLimitLoginCategoryAttributes {
+export const maxPreBlockDuration = 1000 * 60 * 60 * 24 // 1 day
+
+export interface UserLimitLoginCategoryAttributesVersion1 {
familyId: string
userId: string
categoryId: string
}
-export type UserLimitLoginCategoryModel = Sequelize.Model & UserLimitLoginCategoryAttributes
+export interface UserLimitLoginCategoryAttributesVersion2 {
+ preBlockDuration: number
+}
+
+export type UserLimitLoginCategoryAttributes = UserLimitLoginCategoryAttributesVersion1 & UserLimitLoginCategoryAttributesVersion2
+
+export type UserLimitLoginCategoryModel = Sequelize.Model & UserLimitLoginCategoryAttributes
export type UserLimitLoginCategoryModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): UserLimitLoginCategoryModel;
}
-export const attributes: SequelizeAttributes = {
+export const attributesVersion1: SequelizeAttributes = {
familyId: { ...familyIdColumn, primaryKey: true },
userId: { ...idWithinFamilyColumn, primaryKey: true },
categoryId: { ...idWithinFamilyColumn }
}
+export const attributesVersion2: SequelizeAttributes = {
+ preBlockDuration: {
+ type: Sequelize.INTEGER,
+ validate: {
+ min: 0,
+ max: maxPreBlockDuration
+ },
+ allowNull: false,
+ defaultValue: 0
+ }
+}
+
+export const attributes: SequelizeAttributes = {
+ ...attributesVersion1,
+ ...attributesVersion2
+}
+
export const createUserLimitLoginCategoryModel = (sequelize: Sequelize.Sequelize): UserLimitLoginCategoryModelStatic => sequelize.define('UserLimitLoginCategory', attributes) as UserLimitLoginCategoryModelStatic
diff --git a/src/database/utils/nested-transactions.ts b/src/database/utils/nested-transactions.ts
new file mode 100644
index 0000000..a6b5239
--- /dev/null
+++ b/src/database/utils/nested-transactions.ts
@@ -0,0 +1,62 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { generateIdWithinFamily } from '../../util/token'
+import { configItemIds } from '../config'
+import { Database } from '../main'
+
+class NestedTransactionTestException extends Error {}
+class TestRollbackException extends NestedTransactionTestException {}
+class NestedTransactionsNotWorkingException extends NestedTransactionTestException { constructor () { super('NestedTransactionsNotWorkingException') } }
+class IllegalStateException extends NestedTransactionTestException {}
+
+export async function assertNestedTransactionsAreWorking (database: Database) {
+ const testValue = generateIdWithinFamily()
+
+ // clean up just for the case
+ await database.config.destroy({ where: { id: configItemIds.selfTestData } })
+
+ await database.transaction(async (transaction) => {
+ const readOne = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
+
+ if (readOne) throw new IllegalStateException()
+
+ await database.transaction(async (transaction) => {
+ await database.config.create({ id: configItemIds.selfTestData, value: testValue }, { transaction })
+
+ const readTwo = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
+
+ if (readTwo?.value !== testValue) throw new IllegalStateException()
+
+ try {
+ await database.transaction(async (transaction) => {
+ await database.config.destroy({ where: { id: configItemIds.selfTestData }, transaction })
+
+ throw new TestRollbackException()
+ }, { transaction })
+ } catch (ex) {
+ if (!(ex instanceof TestRollbackException)) throw ex
+ }
+
+ const readThree = await database.config.findOne({ where: { id: configItemIds.selfTestData }, transaction })
+
+ if (readThree?.value !== testValue) throw new NestedTransactionsNotWorkingException()
+
+ await database.config.destroy({ where: { id: configItemIds.selfTestData }, transaction })
+ }, { transaction })
+ })
+}
diff --git a/src/database/utils/serialized.ts b/src/database/utils/serialized.ts
new file mode 100644
index 0000000..c05d340
--- /dev/null
+++ b/src/database/utils/serialized.ts
@@ -0,0 +1,107 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { configItemIds } from '../config'
+import { Database } from '../main'
+
+export class SerializationFeatureCheckException extends Error {}
+
+export function shouldRetryWithException (database: Database, e: unknown): boolean {
+ if (e instanceof Sequelize.TimeoutError) return true
+
+ if (!(e instanceof Sequelize.DatabaseError)) return false
+
+ const parent = e.parent
+
+ if (database.dialect === 'sqlite') {
+ if (parent.message.startsWith('SQLITE_BUSY:')) return true
+ } else if (database.dialect === 'postgres') {
+ // 40001 = serialization_failure
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ if ((parent as any).code === '40001') return true
+ // 40P01 = deadlock detected
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ if ((parent as any).code === '40P01') return true
+ } else if (database.dialect === 'mariadb') {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const errno = (parent as any).errno
+
+ // ER_LOCK_DEADLOCK
+ // Deadlock found when trying to get lock; try restarting transaction
+ if (errno === 1213) return true
+ }
+
+ return false
+}
+
+export async function assertSerializeableTransactionsAreWorking (database: Database) {
+ // clean up just for the case
+ await database.config.destroy({
+ where: {
+ id: {
+ [Sequelize.Op.in]: [ configItemIds.selfTestData, configItemIds.secondSelfTestData ]
+ }
+ }
+ })
+
+ // insert specific data
+ await database.config.bulkCreate([
+ {
+ id: configItemIds.selfTestData,
+ value: '123'
+ },
+ {
+ id: configItemIds.secondSelfTestData,
+ value: '456'
+ }
+ ])
+
+ try {
+ // use two parallel transactions
+ await database.transaction(async (transactionOne) => {
+ await database.transaction(async (transactionTwo) => {
+ await database.config.findAll({ transaction: transactionOne })
+ await database.config.findAll({ transaction: transactionTwo })
+
+ await Promise.all([
+ (async () => {
+ await database.config.update({ value: 'c' }, { where: { id: configItemIds.selfTestData }, transaction: transactionOne })
+ })(),
+ (async () => {
+ await database.config.update({ value: 'd' }, { where: { id: configItemIds.secondSelfTestData }, transaction: transactionTwo })
+ })()
+ ])
+ }, { disableRetry: true })
+ }, { disableRetry: true })
+
+ throw new SerializationFeatureCheckException()
+ } catch (ex) {
+ if (!shouldRetryWithException(database, ex)) {
+ throw new SerializationFeatureCheckException()
+ }
+ }
+
+ // finish clean up
+ await database.config.destroy({
+ where: {
+ id: {
+ [Sequelize.Op.in]: [ configItemIds.selfTestData, configItemIds.secondSelfTestData ]
+ }
+ }
+ })
+}
diff --git a/src/function/authentication/index.ts b/src/function/authentication/index.ts
index 7af460e..6351acf 100644
--- a/src/function/authentication/index.ts
+++ b/src/function/authentication/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -19,19 +19,28 @@ import { Unauthorized } from 'http-errors'
import { Database, Transaction } from '../../database'
import { generateAuthToken } from '../../util/token'
-export const createAuthTokenByMailAddress = async ({ mail, database, transaction }: { mail: string, database: Database, transaction: Transaction }) => {
+export const createAuthTokenByMailAddress = async ({
+ mail, database, transaction, locale
+}: {
+ mail: string, database: Database, transaction: Transaction, locale: string
+}) => {
const token = generateAuthToken()
await database.authtoken.create({
token,
mail,
- createdAt: Date.now().toString()
+ createdAt: Date.now().toString(),
+ locale
}, { transaction })
return token
}
-export const getMailByAuthToken = async ({ mailAuthToken, database, transaction }: { mailAuthToken: string, database: Database, transaction: Transaction }) => {
+export const getMailAndLocaleByAuthToken = async ({
+ mailAuthToken, database, transaction, invalidate
+}: {
+ mailAuthToken: string, database: Database, transaction: Transaction, invalidate: boolean
+}) => {
const entry = await database.authtoken.findOne({
where: {
token: mailAuthToken
@@ -40,18 +49,38 @@ export const getMailByAuthToken = async ({ mailAuthToken, database, transaction
})
if (entry) {
- return entry.mail
+ if (invalidate) {
+ const rowCounter = await database.authtoken.destroy({
+ where: {
+ token: mailAuthToken
+ },
+ transaction
+ })
+
+ if (rowCounter !== 1) {
+ return null
+ }
+ }
+
+ return {
+ mail: entry.mail,
+ locale: entry.locale
+ }
} else {
return null
}
}
-export const requireMailByAuthToken = async ({ mailAuthToken, database, transaction }: { mailAuthToken: string, database: Database, transaction: Transaction }) => {
- const mail = await getMailByAuthToken({ mailAuthToken, database, transaction })
+export const requireMailAndLocaleByAuthToken = async ({
+ mailAuthToken, database, transaction, invalidate
+}: {
+ mailAuthToken: string, database: Database, transaction: Transaction, invalidate: boolean
+}) => {
+ const result = await getMailAndLocaleByAuthToken({ mailAuthToken, database, transaction, invalidate })
- if (!mail) {
+ if (!result) {
throw new Unauthorized()
}
- return mail
+ return result
}
diff --git a/src/function/authentication/login-by-mail.ts b/src/function/authentication/login-by-mail.ts
index 5247abb..c36be68 100644
--- a/src/function/authentication/login-by-mail.ts
+++ b/src/function/authentication/login-by-mail.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-import { Forbidden, Gone, TooManyRequests } from 'http-errors'
+import { Forbidden, Gone, TooManyRequests, Unauthorized } from 'http-errors'
import { Database } from '../../database'
import { sendAuthenticationMail } from '../../util/mail'
import { areWordSequencesEqual, randomWords } from '../../util/random-words'
@@ -23,12 +23,52 @@ import { checkMailSendLimit } from '../../util/ratelimit-authmail'
import { generateAuthToken } from '../../util/token'
import { createAuthTokenByMailAddress } from './index'
-export const sendLoginCode = async ({ mail, locale, database }: {
+export const sendLoginCode = async ({ mail, deviceAuthToken, locale, database }: {
mail: string
+ deviceAuthToken?: string
locale: string
database: Database
// no transaction here because this is directly called from an API endpoint
}): Promise<{ mailLoginToken: string }> => {
+ let deviceName = null
+
+ if (deviceAuthToken !== undefined) {
+ const info = await database.transaction(async (transaction) => {
+ const deviceEntryUnsafe = await database.device.findOne({
+ where: { deviceAuthToken },
+ attributes: ['familyId', 'name'],
+ transaction
+ })
+
+ if (!deviceEntryUnsafe) {
+ throw new Unauthorized()
+ }
+
+ const deviceEntry = {
+ familyId: deviceEntryUnsafe.familyId,
+ name: deviceEntryUnsafe.name
+ }
+
+ const userEntryCounter = await database.user.count({
+ where: {
+ familyId: deviceEntry.familyId,
+ mail
+ },
+ transaction
+ })
+
+ if (userEntryCounter === 1) {
+ return { deviceName: deviceEntry.name }
+ } else {
+ // do not show the device name if it is from another family
+ // otherwise third parties could chose a part of the content of the mail
+ return { deviceName: null }
+ }
+ })
+
+ deviceName = info.deviceName
+ }
+
try {
await checkMailSendLimit(mail)
} catch (ex) {
@@ -41,7 +81,8 @@ export const sendLoginCode = async ({ mail, locale, database }: {
await sendAuthenticationMail({
receiver: mail,
code,
- locale
+ locale,
+ deviceName
})
await database.transaction(async (transaction) => {
@@ -50,7 +91,8 @@ export const sendLoginCode = async ({ mail, locale, database }: {
receivedCode: code,
mail,
createdAt: Date.now().toString(10),
- remainingAttempts: 3
+ remainingAttempts: 3,
+ locale
}, { transaction })
})
@@ -67,7 +109,7 @@ export const signInByMailCode = async ({ mailLoginToken, receivedCode, database
database: Database
// no transaction here because this is directly called from an API endpoint
}): Promise<{ mailAuthToken: string }> => {
- return database.transaction(async (transaction) => {
+ const result = await database.transaction(async (transaction) => {
const entry = await database.mailLoginToken.findOne({
where: {
mailLoginToken
@@ -85,14 +127,32 @@ export const signInByMailCode = async ({ mailLoginToken, receivedCode, database
await entry.save({ transaction })
if (entry.remainingAttempts === 0) {
- throw new Gone()
+ return () => { throw new Gone() }
} else {
- throw new Forbidden()
+ return () => { throw new Forbidden() }
}
}
- const mailAuthToken = await createAuthTokenByMailAddress({ mail: entry.mail, database, transaction })
+ const counter = await database.mailLoginToken.destroy({
+ where: {
+ mailLoginToken
+ },
+ transaction
+ })
- return { mailAuthToken }
+ if (counter !== 1) {
+ throw new Gone()
+ }
+
+ const mailAuthToken = await createAuthTokenByMailAddress({
+ mail: entry.mail,
+ locale: entry.locale,
+ database,
+ transaction
+ })
+
+ return () => ({ mailAuthToken })
})
+
+ return result()
}
diff --git a/src/function/child/add-device.ts b/src/function/child/add-device.ts
index 710b569..ede948c 100644
--- a/src/function/child/add-device.ts
+++ b/src/function/child/add-device.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -22,13 +22,22 @@ import { generateAuthToken, generateVersionId } from '../../util/token'
import { WebsocketApi } from '../../websocket'
import { prepareDeviceEntry } from '../device/prepare-device-entry'
import { notifyClientsAboutChangesDelayed } from '../websocket'
+import { generateServerDataStatus } from '../sync/get-server-data-status'
+import { EventHandler } from '../../monitoring/eventhandler'
+import { ServerDataStatus } from '../../object/serverdatastatus'
+import { createEmptyClientDataStatus } from '../../object/clientdatastatus'
-export const addChildDevice = async ({ database, websocket, request }: {
+export const addChildDevice = async ({ database, eventHandler, websocket, request }: {
database: Database
+ eventHandler: EventHandler
websocket: WebsocketApi
request: RegisterChildDeviceRequest
// no transaction here because this is directly called from an API endpoint
-}) => {
+}): Promise<{
+ deviceId: string
+ deviceAuthToken: string
+ data: ServerDataStatus
+}> => {
return database.transaction(async (transaction) => {
const entry = await database.addDeviceToken.findOne({
where: {
@@ -52,7 +61,8 @@ export const addChildDevice = async ({ database, websocket, request }: {
deviceAuthToken,
deviceName: request.deviceName,
newDeviceInfo: request.childDevice,
- userId: ''
+ userId: '',
+ isUserKeptSignedIn: false
}), { transaction })
await database.family.update({
@@ -64,11 +74,29 @@ export const addChildDevice = async ({ database, websocket, request }: {
transaction
})
- await notifyClientsAboutChangesDelayed({ familyId, websocket, database, isImportant: true, sourceDeviceId: deviceId, transaction })
+ await notifyClientsAboutChangesDelayed({
+ familyId,
+ websocket,
+ database,
+ generalLevel: 1,
+ targetedLevels: new Map(),
+ sourceDeviceId: deviceId,
+ transaction
+ })
+
+ const data = await generateServerDataStatus({
+ database,
+ clientStatus: createEmptyClientDataStatus({ clientLevel: request.clientLevel || null }),
+ familyId: entry.familyId,
+ deviceId,
+ transaction,
+ eventHandler
+ })
return {
deviceId,
- deviceAuthToken
+ deviceAuthToken,
+ data
}
})
}
diff --git a/src/function/child/set-primary-device.ts b/src/function/child/set-primary-device.ts
index 6da1e21..4fb6d1a 100644
--- a/src/function/child/set-primary-device.ts
+++ b/src/function/child/set-primary-device.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,7 +16,6 @@
*/
import { Conflict, InternalServerError, Unauthorized } from 'http-errors'
-import * as Sequelize from 'sequelize'
import { config } from '../../config'
import { Database } from '../../database'
import { generateVersionId } from '../../util/token'
@@ -60,7 +59,6 @@ export const setPrimaryDevice = async ({ database, websocket, deviceAuthToken, c
userId: deviceEntry.currentUserId
},
transaction,
- lock: Sequelize.Transaction.LOCK.UPDATE,
attributes: ['currentDevice']
})
@@ -166,7 +164,8 @@ export const setPrimaryDevice = async ({ database, websocket, deviceAuthToken, c
sourceDeviceId: deviceEntry.deviceId,
websocket,
database,
- isImportant: false, // the source device knows it already
+ generalLevel: 1, // the source device knows it already
+ targetedLevels: new Map(),
transaction
})
diff --git a/src/function/cleanup/account-deletion.ts b/src/function/cleanup/account-deletion.ts
new file mode 100644
index 0000000..cf783f5
--- /dev/null
+++ b/src/function/cleanup/account-deletion.ts
@@ -0,0 +1,107 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { Unauthorized } from 'http-errors'
+import { DeleteAccountPayload } from '../../api/schema'
+import { Database } from '../../database'
+import { sendAccountDeletedMail } from '../../util/mail'
+import { WebsocketApi } from '../../websocket'
+import { requireMailAndLocaleByAuthToken } from '../authentication'
+import { deleteFamilies } from './delete-families'
+
+export async function deleteAccount({ request, database, websocket }: {
+ request: DeleteAccountPayload
+ database: Database
+ websocket: WebsocketApi
+}) {
+ await database.transaction(async (transaction) => {
+ const deviceEntryUnsafe = await database.device.findOne({
+ where: { deviceAuthToken: request.deviceAuthToken },
+ attributes: ['familyId'],
+ transaction
+ })
+
+ if (!deviceEntryUnsafe) {
+ throw new Unauthorized()
+ }
+
+ const deviceEntry = {
+ familyId: deviceEntryUnsafe.familyId
+ }
+
+ const userEntries = (await database.user.findAll({
+ where: {
+ familyId: deviceEntry.familyId,
+ type: 'parent'
+ },
+ attributes: ['mail'],
+ transaction
+ })).map((item) => ({ mail: item.mail }))
+
+ const registeredMailAddresses = new Set()
+
+ userEntries.forEach((item) => {
+ if (item.mail !== '') registeredMailAddresses.add(item.mail)
+ })
+
+ const authenticatedMailAddresses = new Set()
+
+ for (const mailAuthToken of request.mailAuthTokens) {
+ const info = await requireMailAndLocaleByAuthToken({
+ mailAuthToken,
+ database,
+ transaction,
+ invalidate: true
+ })
+
+ if (!registeredMailAddresses.has(info.mail)) throw new Unauthorized()
+
+ authenticatedMailAddresses.add(info.mail)
+ }
+
+ if (registeredMailAddresses.size !== authenticatedMailAddresses.size) throw new Unauthorized()
+
+ registeredMailAddresses.forEach((mail) => {
+ if (!authenticatedMailAddresses.has(mail)) throw new Unauthorized()
+ })
+
+ const deviceEntries = (await database.device.findAll({
+ where: {
+ familyId: deviceEntry.familyId
+ },
+ transaction,
+ attributes: ['deviceAuthToken']
+ })).map((item) => ({ deviceAuthToken: item.deviceAuthToken }))
+
+ await deleteFamilies({ database, transaction, familiyIds: [deviceEntry.familyId] })
+
+ transaction.afterCommit(() => {
+ for (const device of deviceEntries) {
+ websocket.triggerSyncByDeviceAuthToken({
+ deviceAuthToken: device.deviceAuthToken,
+ isImportant: true
+ })
+ }
+
+ registeredMailAddresses.forEach((receiver) => {
+ sendAccountDeletedMail({ receiver }).catch((ex) => {
+ console.warn('failure while sending account deletion confirmation', ex)
+ })
+ })
+ })
+ })
+}
diff --git a/src/function/cleanup/delete-families.ts b/src/function/cleanup/delete-families.ts
index 6e19993..cf65f86 100644
--- a/src/function/cleanup/delete-families.ts
+++ b/src/function/cleanup/delete-families.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -17,10 +17,11 @@
import { difference } from 'lodash'
import * as Sequelize from 'sequelize'
-import { Database } from '../../database'
+import { Database, Transaction } from '../../database'
-export async function deleteFamilies ({ database, familiyIds }: {
+export async function deleteFamilies ({ database, transaction, familiyIds }: {
database: Database
+ transaction: Transaction
familiyIds: Array
// no transaction here because this should run isolated
}) {
@@ -28,138 +29,126 @@ export async function deleteFamilies ({ database, familiyIds }: {
return
}
- await database.transaction(async (transaction) => {
- // app
- await database.app.destroy({
- where: {
- familyId: {
- [Sequelize.Op.in]: familiyIds
- }
- },
- transaction
- })
-
- // app activity
- await database.appActivity.destroy({
- where: {
- familyId: {
- [Sequelize.Op.in]: familiyIds
- }
- },
- transaction
- })
-
- // category
- await database.category.destroy({
- where: {
- familyId: {
- [Sequelize.Op.in]: familiyIds
- }
- },
- transaction
- })
-
- // categoryapp
- await database.categoryApp.destroy({
- where: {
- familyId: {
- [Sequelize.Op.in]: familiyIds
- }
- },
- transaction
- })
-
- // purchase
- await database.purchase.destroy({
- where: {
- familyId: {
- [Sequelize.Op.in]: familiyIds
- }
- },
- transaction
- })
-
- // timelimitrule
- await database.timelimitRule.destroy({
- where: {
- familyId: {
- [Sequelize.Op.in]: familiyIds
- }
- },
- transaction
- })
-
- // usedtime
- await database.usedTime.destroy({
- where: {
- familyId: {
- [Sequelize.Op.in]: familiyIds
- }
- },
- transaction
- })
-
- // user
- await database.user.destroy({
- where: {
- familyId: {
- [Sequelize.Op.in]: familiyIds
- }
- },
- transaction
- })
-
- // device
- const oldDeviceAuthTokens = await database.device.findAll({
- where: {
- familyId: {
- [Sequelize.Op.in]: familiyIds
- }
- },
- attributes: ['deviceAuthToken'],
- transaction
- }).map((item) => item.deviceAuthToken)
-
- await database.device.destroy({
- where: {
- familyId: {
- [Sequelize.Op.in]: familiyIds
- }
- },
- transaction
- })
-
- // olddevice
- if (oldDeviceAuthTokens.length > 0) {
- const knownOldDeviceAuthTokens = await database.oldDevice.findAll({
- where: {
- deviceAuthToken: {
- [Sequelize.Op.in]: oldDeviceAuthTokens
- }
- },
- transaction
- }).map((item) => item.deviceAuthToken)
-
- const oldDeviceAuthTokensToAdd = difference(oldDeviceAuthTokens, knownOldDeviceAuthTokens)
-
- if (oldDeviceAuthTokensToAdd.length > 0) {
- await database.oldDevice.bulkCreate(
- oldDeviceAuthTokensToAdd.map((item) => ({
- deviceAuthToken: item
- })),
- { transaction }
- )
+ // category
+ await database.category.destroy({
+ where: {
+ familyId: {
+ [Sequelize.Op.in]: familiyIds
}
- }
+ },
+ transaction
+ })
- // family
- await database.family.destroy({
+ // categoryapp
+ await database.categoryApp.destroy({
+ where: {
+ familyId: {
+ [Sequelize.Op.in]: familiyIds
+ }
+ },
+ transaction
+ })
+
+ // purchase
+ await database.purchase.destroy({
+ where: {
+ familyId: {
+ [Sequelize.Op.in]: familiyIds
+ }
+ },
+ transaction
+ })
+
+ // timelimitrule
+ await database.timelimitRule.destroy({
+ where: {
+ familyId: {
+ [Sequelize.Op.in]: familiyIds
+ }
+ },
+ transaction
+ })
+
+ // usedtime
+ await database.usedTime.destroy({
+ where: {
+ familyId: {
+ [Sequelize.Op.in]: familiyIds
+ }
+ },
+ transaction
+ })
+
+ // session durations
+ await database.sessionDuration.destroy({
+ where: {
+ familyId: {
+ [Sequelize.Op.in]: familiyIds
+ }
+ },
+ transaction
+ })
+
+ // user
+ await database.user.destroy({
+ where: {
+ familyId: {
+ [Sequelize.Op.in]: familiyIds
+ }
+ },
+ transaction
+ })
+
+ // device
+ const oldDeviceAuthTokens = (await database.device.findAll({
+ where: {
+ familyId: {
+ [Sequelize.Op.in]: familiyIds
+ }
+ },
+ attributes: ['deviceAuthToken'],
+ transaction
+ })).map((item) => item.deviceAuthToken)
+
+ await database.device.destroy({
+ where: {
+ familyId: {
+ [Sequelize.Op.in]: familiyIds
+ }
+ },
+ transaction
+ })
+
+ // olddevice
+ if (oldDeviceAuthTokens.length > 0) {
+ const knownOldDeviceAuthTokens = (await database.oldDevice.findAll({
where: {
- familyId: {
- [Sequelize.Op.in]: familiyIds
+ deviceAuthToken: {
+ [Sequelize.Op.in]: oldDeviceAuthTokens
}
},
transaction
- })
+ })).map((item) => item.deviceAuthToken)
+
+ const oldDeviceAuthTokensToAdd = difference(oldDeviceAuthTokens, knownOldDeviceAuthTokens)
+
+ if (oldDeviceAuthTokensToAdd.length > 0) {
+ await database.oldDevice.bulkCreate(
+ oldDeviceAuthTokensToAdd.map((item) => ({
+ deviceAuthToken: item
+ })),
+ { transaction }
+ )
+ }
+ }
+
+ // family
+ await database.family.destroy({
+ where: {
+ familyId: {
+ [Sequelize.Op.in]: familiyIds
+ }
+ },
+ transaction
})
}
diff --git a/src/function/cleanup/delete-old-families.ts b/src/function/cleanup/delete-old-families.ts
index f4a407c..2f6bf6b 100644
--- a/src/function/cleanup/delete-old-families.ts
+++ b/src/function/cleanup/delete-old-families.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -26,16 +26,19 @@ export async function deleteOldFamilies (database: Database) {
if (oldFamilyIds.length > 0) {
const familyIdsToDelete = oldFamilyIds.slice(0, 256) /* limit to 256 families per execution */
- await deleteFamilies({
- database,
- familiyIds: familyIdsToDelete
+ await database.transaction(async (transaction) => {
+ await deleteFamilies({
+ database,
+ transaction,
+ familiyIds: familyIdsToDelete
+ })
})
}
}
export async function findOldFamilyIds (database: Database) {
return database.transaction(async (transaction) => {
- const familyIdsWithExpiredLicenses = await database.family.findAll({
+ const familyIdsWithExpiredLicenses = (await database.family.findAll({
where: {
fullVersionUntil: {
[Sequelize.Op.lt]: (Date.now() - 1000 * 60 * 60 * 24 * 90 /* 90 days */).toString(10)
@@ -43,13 +46,13 @@ export async function findOldFamilyIds (database: Database) {
},
attributes: ['familyId'],
transaction
- }).map((item) => item.familyId)
+ })).map((item) => item.familyId)
if (familyIdsWithExpiredLicenses.length === 0) {
return []
}
- const recentlyUsedFamilyIds = await database.device.findAll({
+ const recentlyUsedFamilyIds = (await database.device.findAll({
where: {
familyId: {
[Sequelize.Op.in]: familyIdsWithExpiredLicenses
@@ -60,7 +63,7 @@ export async function findOldFamilyIds (database: Database) {
},
attributes: ['familyId'],
transaction
- }).map((item) => item.familyId)
+ })).map((item) => item.familyId)
return difference(familyIdsWithExpiredLicenses, recentlyUsedFamilyIds)
})
diff --git a/src/function/device/prepare-device-entry.ts b/src/function/device/prepare-device-entry.ts
index e0c9edc..7198b32 100644
--- a/src/function/device/prepare-device-entry.ts
+++ b/src/function/device/prepare-device-entry.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -19,13 +19,14 @@ import { NewDeviceInfo } from '../../api/schema'
import { DeviceAttributes } from '../../database/device'
import { generateVersionId } from '../../util/token'
-export const prepareDeviceEntry = ({ familyId, userId, deviceAuthToken, deviceId, deviceName, newDeviceInfo }: {
+export const prepareDeviceEntry = ({ familyId, userId, deviceAuthToken, deviceId, deviceName, newDeviceInfo, isUserKeptSignedIn }: {
familyId: string
userId: string
deviceAuthToken: string
deviceId: string
deviceName: string
newDeviceInfo: NewDeviceInfo
+ isUserKeptSignedIn: boolean
}): DeviceAttributes => ({
familyId,
deviceId,
@@ -52,7 +53,7 @@ export const prepareDeviceEntry = ({ familyId, userId, deviceAuthToken, deviceId
lastConnectivity: '0',
notSeenForLongTime: false,
didDeviceReportUninstall: false,
- isUserKeptSignedIn: false,
+ isUserKeptSignedIn,
showDeviceConnected: false,
defaultUserId: '',
defaultUserTimeout: 0,
@@ -62,5 +63,10 @@ export const prepareDeviceEntry = ({ familyId, userId, deviceAuthToken, deviceId
asEnabled: false,
wasAsEnabled: false,
activityLevelBlocking: false,
- isQorLater: false
+ isQorLater: false,
+ manipulationFlags: 0,
+ publicKey: null,
+ nextKeyReplySequenceNumber: '1',
+ platformType: null,
+ platformLevel: 0
})
diff --git a/src/function/device/remove-device.ts b/src/function/device/remove-device.ts
index c4fad70..87e09db 100644
--- a/src/function/device/remove-device.ts
+++ b/src/function/device/remove-device.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -40,23 +40,6 @@ export async function removeDevice ({ database, familyId, deviceId, websocket, t
throw new Conflict()
}
- // remove app entries
- await database.app.destroy({
- where: {
- familyId,
- deviceId
- },
- transaction
- })
-
- await database.appActivity.destroy({
- where: {
- familyId,
- deviceId
- },
- transaction
- })
-
// remove as current device
await database.user.update({
currentDevice: ''
@@ -104,7 +87,8 @@ export async function removeDevice ({ database, familyId, deviceId, websocket, t
websocket,
familyId,
sourceDeviceId: null,
- isImportant: false,
+ generalLevel: 1,
+ targetedLevels: new Map(),
transaction
})
diff --git a/src/function/device/report-device-removed.ts b/src/function/device/report-device-removed.ts
index 3f40c66..bfda3a7 100644
--- a/src/function/device/report-device-removed.ts
+++ b/src/function/device/report-device-removed.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -41,7 +41,7 @@ export async function reportDeviceRemoved ({ database, deviceAuthToken, websocke
deviceEntry.didDeviceReportUninstall = true
deviceEntry.deviceAuthToken = generateAuthToken() // invalidiate the token
- deviceEntry.save({ transaction })
+ await deviceEntry.save({ transaction })
// invalidiate device list
await database.family.update({
@@ -65,7 +65,8 @@ export async function reportDeviceRemoved ({ database, deviceAuthToken, websocke
websocket,
familyId: deviceEntry.familyId,
sourceDeviceId: null,
- isImportant: false,
+ generalLevel: 1,
+ targetedLevels: new Map(),
transaction
})
diff --git a/src/function/dh/decrypt.ts b/src/function/dh/decrypt.ts
new file mode 100644
index 0000000..bd6534c
--- /dev/null
+++ b/src/function/dh/decrypt.ts
@@ -0,0 +1,85 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { createDecipheriv } from 'crypto'
+import { Database } from '../../database'
+import { isVersionId } from '../../util/token'
+import { getSharedSecret, SharedSecretException } from './shared-secret'
+
+export async function decrypt({
+ database, transaction, familyId, deviceId, encryptedData, authData
+}: {
+ database: Database
+ transaction: Sequelize.Transaction
+ familyId: string
+ deviceId: string
+ encryptedData: string
+ authData: Buffer
+}) {
+ const parts = encryptedData.split('.')
+
+ if (parts.length !== 3) throw new MalformedDataDecryptException('expected three parts')
+
+ const ivAndEncrypted = Buffer.from(parts[0], 'base64')
+ const otherPublicKey = Buffer.from(parts[1], 'base64')
+ const keyId = parts[2]
+
+ if (ivAndEncrypted.length < 12 + 16) throw new MalformedDataDecryptException('too short for iv and auth tag')
+
+ if (!isVersionId(keyId)) throw new KeyNotFoundDecryptException('invalid key id')
+
+ const sharedSecret = await (async () => {
+ try {
+ return getSharedSecret({
+ database,
+ transaction,
+ familyId,
+ deviceId,
+ keyId,
+ otherPublicKey
+ })
+ } catch (ex) {
+ if (ex instanceof SharedSecretException) throw new SharedSecretDecryptException(ex)
+ throw ex
+ }
+ })()
+
+ try {
+ const decipher = createDecipheriv('aes-128-gcm', sharedSecret.sharedSecret.slice(0, 16), ivAndEncrypted.slice(0, 12), {
+ authTagLength: 16
+ })
+
+ decipher.setAuthTag(ivAndEncrypted.slice(ivAndEncrypted.length - 16, ivAndEncrypted.length))
+ decipher.setAAD(authData)
+
+ const decryptedData = Buffer.concat([
+ decipher.update(ivAndEncrypted.slice(12, ivAndEncrypted.length - 16)),
+ decipher.final()
+ ])
+
+ return decryptedData
+ } catch (ex) {
+ throw new MalformedAuthenticationException()
+ }
+}
+
+export class DecryptException extends Error {}
+class SharedSecretDecryptException extends DecryptException { constructor(cause: Error) { super(cause.message) } }
+class MalformedDataDecryptException extends DecryptException { constructor(message: string) { super('malformed data: ' + message) } }
+class MalformedAuthenticationException extends DecryptException { constructor() { super('authentication data') } }
+class KeyNotFoundDecryptException extends DecryptException { constructor(message: string) { super('key not found: ' + message) } }
diff --git a/src/function/dh/genkey.ts b/src/function/dh/genkey.ts
new file mode 100644
index 0000000..df4b3ec
--- /dev/null
+++ b/src/function/dh/genkey.ts
@@ -0,0 +1,38 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { generateKeyPair } from 'crypto'
+import { promisify } from 'util'
+
+const generateKeyPairAsync = promisify(generateKeyPair)
+
+export async function generateDhKeypair() {
+ return await generateKeyPairAsync(
+ 'ec',
+ {
+ namedCurve: 'prime256v1',
+ publicKeyEncoding: {
+ type: 'spki',
+ format: 'der'
+ },
+ privateKeyEncoding: {
+ type: 'pkcs8',
+ format: 'der'
+ }
+ }
+ )
+}
diff --git a/src/function/dh/index.ts b/src/function/dh/index.ts
new file mode 100644
index 0000000..99719da
--- /dev/null
+++ b/src/function/dh/index.ts
@@ -0,0 +1,21 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+export { decrypt } from './decrypt'
+export { generateDhKeypair } from './genkey'
+export { decryptParentPassword } from './parentpassword'
+export { getSharedSecret, SharedSecretException } from './shared-secret'
diff --git a/src/function/dh/parentpassword.ts b/src/function/dh/parentpassword.ts
new file mode 100644
index 0000000..322cee7
--- /dev/null
+++ b/src/function/dh/parentpassword.ts
@@ -0,0 +1,56 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { Cache } from '../sync/apply-actions/cache'
+import { ApplyActionException } from '../sync/apply-actions/exception'
+import {
+ EncryptableParentPassword, assertParentPasswordValid,
+ PlaintextParentPassword, ParentPasswordValidationException
+} from '../../api/schema'
+import { decrypt, DecryptException } from './decrypt'
+
+export async function decryptParentPassword({ cache, password } : {
+ cache: Cache
+ password: EncryptableParentPassword
+}): Promise {
+ if (!password.encrypted) return password
+
+ try {
+ const secondHash = (await decrypt({
+ database: cache.database,
+ transaction: cache.transaction,
+ familyId: cache.familyId,
+ deviceId: cache.deviceId,
+ encryptedData: password.secondHash,
+ authData: Buffer.from(`ParentPassword:${password.hash}:${password.secondSalt}`, 'ascii')
+ })).toString('ascii')
+
+ const result: PlaintextParentPassword = {
+ hash: password.hash,
+ secondSalt: password.secondSalt,
+ secondHash
+ }
+
+ assertParentPasswordValid(result)
+
+ return result
+ } catch (ex) {
+ if (ex instanceof DecryptException) throw new ApplyActionException({ staticMessage: ex.message })
+ else if (ex instanceof ParentPasswordValidationException) throw new ApplyActionException({ staticMessage: 'invalid encrypted parent password' })
+ else throw ex
+ }
+}
diff --git a/src/function/dh/shared-secret.ts b/src/function/dh/shared-secret.ts
new file mode 100644
index 0000000..257c7c1
--- /dev/null
+++ b/src/function/dh/shared-secret.ts
@@ -0,0 +1,100 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { createPrivateKey, createPublicKey, diffieHellman } from 'crypto'
+import { Database } from '../../database'
+import { calculateExpireTime } from '../../database/devicedhkey'
+import { isVersionId } from '../../util/token'
+
+export async function getSharedSecret({
+ database, transaction, familyId, deviceId, keyId, otherPublicKey
+}: {
+ database: Database
+ transaction: Sequelize.Transaction
+ familyId: string
+ deviceId: string
+ keyId: string
+ otherPublicKey: Buffer
+}) {
+ if (!isVersionId(keyId)) throw new KeyNotFoundException('invalid key id')
+
+ const databaseKeyEntry = await database.deviceDhKey.findOne({
+ where: {
+ familyId,
+ deviceId,
+ version: keyId
+ },
+ transaction
+ })
+
+ if (!databaseKeyEntry) throw new KeyNotFoundException('private key not found')
+
+ if (databaseKeyEntry.expireAt === null) {
+ databaseKeyEntry.expireAt = calculateExpireTime(BigInt(Date.now())).toString(10)
+ await databaseKeyEntry.save({ transaction })
+ } else {
+ if (BigInt(databaseKeyEntry.expireAt) < BigInt(Date.now())) throw new KeyExpiredException()
+ }
+
+ const privateKey = (() => {
+ try {
+ return createPrivateKey({
+ key: databaseKeyEntry.privateKey,
+ format: 'der',
+ type: 'pkcs8'
+ })
+ } catch (ex) {
+ throw new MalformedPrivateKeyException()
+ }
+ })()
+
+ const decodedOtherPublicKey = (() => {
+ try {
+ return createPublicKey({
+ key: otherPublicKey,
+ format: 'der',
+ type: 'spki'
+ })
+ } catch (ex) {
+ throw new MalformedPublicKeyException()
+ }
+ })()
+
+ const sharedSecret = (() => {
+ try {
+ return diffieHellman({
+ privateKey,
+ publicKey: decodedOtherPublicKey
+ })
+ } catch (ex) {
+ throw new MalformedNoMatchingKeysException()
+ }
+ })()
+
+ return {
+ sharedSecret,
+ ownPublicKey: databaseKeyEntry.publicKey
+ }
+}
+
+export class SharedSecretException extends Error {}
+class MalformedPrivateKeyException extends SharedSecretException { constructor() { super('private key') } }
+class MalformedPublicKeyException extends SharedSecretException { constructor() { super('public key') } }
+class MalformedNoMatchingKeysException extends SharedSecretException { constructor() { super('no matching keys') } }
+class KeyExpiredException extends SharedSecretException { constructor() { super('key expired') } }
+class KeyNotFoundException extends SharedSecretException { constructor(message: string) { super('key not found: ' + message) } }
diff --git a/src/function/parent/can-recover-password.ts b/src/function/parent/can-recover-password.ts
deleted file mode 100644
index 302a526..0000000
--- a/src/function/parent/can-recover-password.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import { Database } from '../../database'
-import { requireMailByAuthToken } from '../authentication'
-
-export const canRecoverPassword = async ({ database, mailAuthToken, parentUserId }: {
- database: Database
- mailAuthToken: string
- parentUserId: string
- // no transaction here because this is directly called from an API endpoint
-}): Promise => {
- return database.transaction(async (transaction) => {
- const mail = await requireMailByAuthToken({ mailAuthToken, database, transaction })
-
- const entry = await database.user.findOne({
- where: {
- mail,
- userId: parentUserId,
- type: 'parent'
- },
- transaction
- })
-
- return !!entry
- })
-}
diff --git a/src/function/parent/create-family.ts b/src/function/parent/create-family.ts
index 54262df..475a1cf 100644
--- a/src/function/parent/create-family.ts
+++ b/src/function/parent/create-family.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,37 +16,53 @@
*/
import { Conflict } from 'http-errors'
-import { NewDeviceInfo, ParentPassword } from '../../api/schema'
+import { generateServerDataStatus } from '../sync/get-server-data-status'
+import { NewDeviceInfo, PlaintextParentPassword, assertPlaintextParentPasswordValid } from '../../api/schema'
import { Database } from '../../database'
+import { maxMailNotificationFlags } from '../../database/user'
+import { EventHandler } from '../../monitoring/eventhandler'
+import { ServerDataStatus } from '../../object/serverdatastatus'
+import { createEmptyClientDataStatus } from '../../object/clientdatastatus'
import {
generateAuthToken, generateFamilyId, generateIdWithinFamily, generateVersionId
} from '../../util/token'
-import { requireMailByAuthToken } from '../authentication'
+import { requireMailAndLocaleByAuthToken } from '../authentication'
import { prepareDeviceEntry } from '../device/prepare-device-entry'
-export const createFamily = async ({ database, mailAuthToken, firstParentDevice, password, timeZone, parentName, deviceName }: {
- database: Database,
- mailAuthToken: string,
- firstParentDevice: NewDeviceInfo,
- password: ParentPassword,
- timeZone: string,
- parentName: string,
+export async function createFamily ({
+ database, eventHandler, mailAuthToken, firstParentDevice,
+ password, timeZone, parentName, deviceName, clientLevel
+}: {
+ database: Database
+ eventHandler: EventHandler
+ mailAuthToken: string
+ firstParentDevice: NewDeviceInfo
+ password: PlaintextParentPassword
+ timeZone: string
+ parentName: string
deviceName: string
+ clientLevel: number | null
// no transaction here because this is directly called from an API endpoint
-}) => {
+}): Promise<{
+ deviceAuthToken: string
+ deviceId: string
+ data: ServerDataStatus
+}> {
+ assertPlaintextParentPasswordValid(password)
+
return database.transaction(async (transaction) => {
const now = Date.now().toString(10)
- const mail = await requireMailByAuthToken({ database, mailAuthToken, transaction })
+ const mailInfo = await requireMailAndLocaleByAuthToken({ database, mailAuthToken, transaction, invalidate: true })
// ensure that no family was created for this mail yet
- const exisitngUserEntry = await database.user.findOne({
+ const existingUserEntry = await database.user.findOne({
where: {
- mail
+ mail: mailInfo.mail
},
transaction
})
- if (exisitngUserEntry) {
+ if (existingUserEntry) {
throw new Conflict()
}
@@ -64,7 +80,9 @@ export const createFamily = async ({ database, mailAuthToken, firstParentDevice,
deviceListVersion: generateVersionId(),
// 14 days demo version
fullVersionUntil: (Date.now() + 1000 * 60 * 60 * 24 * 14).toString(10),
- hasFullVersion: true
+ hasFullVersion: true,
+ nextServerKeyRequestSeq: '1',
+ u2fKeysVersion: generateVersionId()
}, { transaction })
// create parent user
@@ -76,13 +94,13 @@ export const createFamily = async ({ database, mailAuthToken, firstParentDevice,
secondPasswordHash: password.secondHash,
secondPasswordSalt: password.secondSalt,
type: 'parent',
- mail,
+ mail: mailInfo.mail,
timeZone,
disableTimelimitsUntil: '0',
currentDevice: '',
categoryForNotAssignedApps: '',
relaxPrimaryDeviceRule: false,
- mailNotificationFlags: 1, // enable warning notifications
+ mailNotificationFlags: maxMailNotificationFlags,
blockedTimes: '',
flags: '0'
}, { transaction })
@@ -94,12 +112,23 @@ export const createFamily = async ({ database, mailAuthToken, firstParentDevice,
deviceName,
newDeviceInfo: firstParentDevice,
userId,
- deviceAuthToken
+ deviceAuthToken,
+ isUserKeptSignedIn: true
}), { transaction })
+ const data = await generateServerDataStatus({
+ database,
+ clientStatus: createEmptyClientDataStatus({ clientLevel }),
+ familyId,
+ deviceId,
+ transaction,
+ eventHandler
+ })
+
return {
deviceAuthToken,
- deviceId
+ deviceId,
+ data
}
})
}
diff --git a/src/function/parent/get-status-by-mail-address.ts b/src/function/parent/get-status-by-mail-address.ts
index 80efb86..1f5d967 100644
--- a/src/function/parent/get-status-by-mail-address.ts
+++ b/src/function/parent/get-status-by-mail-address.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -17,7 +17,7 @@
import { Database, Transaction } from '../../database'
import { StaticMessageException } from '../../exception'
-import { requireMailByAuthToken } from '../authentication'
+import { requireMailAndLocaleByAuthToken } from '../authentication'
const getStatusByMailAddress = async ({
mail, database, transaction
@@ -43,7 +43,9 @@ const getStatusByMailAddress = async ({
export const getStatusByMailToken = async ({
mailAuthToken, database, transaction
}: { mailAuthToken: string, database: Database, transaction: Transaction }) => {
- const mail = await requireMailByAuthToken({ mailAuthToken, database, transaction })
+ const mailInfo = await requireMailAndLocaleByAuthToken({ mailAuthToken, database, transaction, invalidate: false })
+ const mail = mailInfo.mail
+
const status = await getStatusByMailAddress({ mail, database, transaction })
return { mail, status }
diff --git a/src/function/parent/link-mail-address.ts b/src/function/parent/link-mail-address.ts
index 7c3ecb6..4d0661f 100644
--- a/src/function/parent/link-mail-address.ts
+++ b/src/function/parent/link-mail-address.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,11 +16,10 @@
*/
import { Conflict, Unauthorized } from 'http-errors'
-import * as Sequelize from 'sequelize'
import { Database } from '../../database'
import { generateVersionId } from '../../util/token'
import { WebsocketApi } from '../../websocket'
-import { requireMailByAuthToken } from '../authentication'
+import { requireMailAndLocaleByAuthToken } from '../authentication'
import { notifyClientsAboutChangesDelayed } from '../websocket'
export const linkMailAddress = async ({ mailAuthToken, deviceAuthToken, parentUserId, parentPasswordSecondHash, database, websocket }: {
@@ -46,11 +45,11 @@ export const linkMailAddress = async ({ mailAuthToken, deviceAuthToken, parentUs
const familyId = deviceEntry.familyId
- const mailAddress = await requireMailByAuthToken({ mailAuthToken, database, transaction })
+ const mailInfo = await requireMailAndLocaleByAuthToken({ mailAuthToken, database, transaction, invalidate: true })
const exisitingUser = await database.user.findOne({
where: {
- mail: mailAddress
+ mail: mailInfo.mail
},
transaction
})
@@ -65,8 +64,7 @@ export const linkMailAddress = async ({ mailAuthToken, deviceAuthToken, parentUs
familyId,
userId: parentUserId
},
- transaction,
- lock: Sequelize.Transaction.LOCK.UPDATE
+ transaction
})
if (!parentEntry) {
@@ -85,7 +83,7 @@ export const linkMailAddress = async ({ mailAuthToken, deviceAuthToken, parentUs
throw new Conflict()
}
- parentEntry.mail = mailAddress
+ parentEntry.mail = mailInfo.mail
await parentEntry.save({ transaction })
@@ -103,9 +101,10 @@ export const linkMailAddress = async ({ mailAuthToken, deviceAuthToken, parentUs
await notifyClientsAboutChangesDelayed({
familyId,
sourceDeviceId: null,
+ generalLevel: 1,
+ targetedLevels: new Map(),
database,
websocket,
- isImportant: true,
transaction
})
})
diff --git a/src/function/parent/recover-parent-password.ts b/src/function/parent/recover-parent-password.ts
index 3040a99..056234a 100644
--- a/src/function/parent/recover-parent-password.ts
+++ b/src/function/parent/recover-parent-password.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,27 +16,30 @@
*/
import { Conflict } from 'http-errors'
-import { ParentPassword } from '../../api/schema'
+import { PlaintextParentPassword, assertPlaintextParentPasswordValid } from '../../api/schema'
import { Database } from '../../database'
+import { sendPasswordRecoveryUsedMail } from '../../util/mail'
import { generateVersionId } from '../../util/token'
import { WebsocketApi } from '../../websocket'
-import { requireMailByAuthToken } from '../authentication'
+import { requireMailAndLocaleByAuthToken } from '../authentication'
import { notifyClientsAboutChangesDelayed } from '../websocket'
export const recoverParentPassword = async ({ database, websocket, password, mailAuthToken }: {
database: Database
websocket: WebsocketApi
- password: ParentPassword
+ password: PlaintextParentPassword
mailAuthToken: string
// no transaction here because this is directly called from an API endpoint
}) => {
+ assertPlaintextParentPasswordValid(password)
+
await database.transaction(async (transaction) => {
- const mail = await requireMailByAuthToken({ mailAuthToken, database, transaction })
+ const mailInfo = await requireMailAndLocaleByAuthToken({ mailAuthToken, database, transaction, invalidate: true })
// update the user entry
const userEntry = await database.user.findOne({
where: {
- mail
+ mail: mailInfo.mail
},
transaction
})
@@ -65,9 +68,17 @@ export const recoverParentPassword = async ({ database, websocket, password, mai
database,
familyId: userEntry.familyId,
websocket,
- isImportant: true,
+ generalLevel: 2,
+ targetedLevels: new Map(),
sourceDeviceId: null,
transaction
})
+
+ transaction.afterCommit(async () => {
+ await sendPasswordRecoveryUsedMail({
+ receiver: mailInfo.mail,
+ locale: mailInfo.locale
+ })
+ })
})
}
diff --git a/src/function/parent/sign-in-into-family.ts b/src/function/parent/sign-in-into-family.ts
index 4da0527..8637b4e 100644
--- a/src/function/parent/sign-in-into-family.ts
+++ b/src/function/parent/sign-in-into-family.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -18,26 +18,33 @@
import { Conflict } from 'http-errors'
import { NewDeviceInfo } from '../../api/schema'
import { Database } from '../../database'
+import { sendDeviceLinkedMail } from '../../util/mail'
import { generateAuthToken, generateIdWithinFamily, generateVersionId } from '../../util/token'
import { WebsocketApi } from '../../websocket'
-import { requireMailByAuthToken } from '../authentication'
+import { requireMailAndLocaleByAuthToken } from '../authentication'
import { prepareDeviceEntry } from '../device/prepare-device-entry'
import { notifyClientsAboutChangesDelayed } from '../websocket'
+import { generateServerDataStatus } from '../sync/get-server-data-status'
+import { EventHandler } from '../../monitoring/eventhandler'
+import { ServerDataStatus } from '../../object/serverdatastatus'
+import { createEmptyClientDataStatus } from '../../object/clientdatastatus'
-export const signInIntoFamily = async ({ database, mailAuthToken, newDeviceInfo, deviceName, websocket }: {
+export const signInIntoFamily = async ({ database, eventHandler, mailAuthToken, newDeviceInfo, deviceName, websocket, clientLevel }: {
database: Database
+ eventHandler: EventHandler
mailAuthToken: string
newDeviceInfo: NewDeviceInfo
deviceName: string
websocket: WebsocketApi
+ clientLevel: number | null
// no transaction here because this is directly called from an API endpoint
-}): Promise<{ deviceId: string; deviceAuthToken: string }> => {
+}): Promise<{ deviceId: string; deviceAuthToken: string; data: ServerDataStatus }> => {
return database.transaction(async (transaction) => {
- const mail = await requireMailByAuthToken({ database, mailAuthToken, transaction })
+ const mailInfo = await requireMailAndLocaleByAuthToken({ database, mailAuthToken, transaction, invalidate: true })
const userEntryUnsafe = await database.user.findOne({
where: {
- mail
+ mail: mailInfo.mail
},
attributes: ['familyId', 'userId'],
transaction
@@ -61,7 +68,8 @@ export const signInIntoFamily = async ({ database, mailAuthToken, newDeviceInfo,
userId: userEntry.userId,
deviceName,
deviceAuthToken,
- newDeviceInfo
+ newDeviceInfo,
+ isUserKeptSignedIn: true
}), { transaction })
// notify about changes
@@ -78,14 +86,33 @@ export const signInIntoFamily = async ({ database, mailAuthToken, newDeviceInfo,
familyId: userEntry.familyId,
websocket,
database,
- isImportant: true,
+ generalLevel: 1,
+ targetedLevels: new Map(),
sourceDeviceId: deviceId,
transaction
})
+ transaction.afterCommit(async () => {
+ await sendDeviceLinkedMail({
+ receiver: mailInfo.mail,
+ locale: mailInfo.locale,
+ deviceName
+ })
+ })
+
+ const data = await generateServerDataStatus({
+ database,
+ clientStatus: createEmptyClientDataStatus({ clientLevel }),
+ familyId: userEntry.familyId,
+ deviceId,
+ transaction,
+ eventHandler
+ })
+
return {
deviceId,
- deviceAuthToken
+ deviceAuthToken,
+ data
}
})
}
diff --git a/src/function/purchase/add-purchase.ts b/src/function/purchase/add-purchase.ts
index 5078155..ed11fdf 100644
--- a/src/function/purchase/add-purchase.ts
+++ b/src/function/purchase/add-purchase.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,7 +16,6 @@
*/
import { Conflict } from 'http-errors'
-import * as Sequelize from 'sequelize'
import { Database, Transaction } from '../../database'
import { notifyClientsAboutChangesDelayed } from '../../function/websocket'
import { WebsocketApi } from '../../websocket'
@@ -25,16 +24,15 @@ const day = 1000 * 60 * 60 * 24
const month = day * 31
const year = day * 366
-export const addPurchase = async ({ database, familyId, type, transactionId, websocket, transaction }: {
+export const addPurchase = async ({ database, familyId, type, service, transactionId, websocket, transaction }: {
database: Database
familyId: string
type: 'month' | 'year'
+ service: 'googleplay' | 'directpurchase'
transactionId: string
websocket: WebsocketApi
transaction: Transaction
}) => {
- const service = 'googleplay'
-
const oldPurchaseEntry = await database.purchase.findOne({
where: {
service,
@@ -51,8 +49,7 @@ export const addPurchase = async ({ database, familyId, type, transactionId, web
where: {
familyId
},
- transaction,
- lock: Sequelize.Transaction.LOCK.UPDATE
+ transaction
})
if (!familyEntry) {
@@ -85,7 +82,8 @@ export const addPurchase = async ({ database, familyId, type, transactionId, web
sourceDeviceId: null,
database,
websocket,
- isImportant: true,
+ generalLevel: 2,
+ targetedLevels: new Map(),
transaction
})
}
diff --git a/src/function/purchase/iab_verifierr.ts b/src/function/purchase/iab_verifierr.ts
new file mode 100644
index 0000000..0e0f012
--- /dev/null
+++ b/src/function/purchase/iab_verifierr.ts
@@ -0,0 +1,48 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) Paul Crawford
+ * Copyright (c) 2020 Jonas Lochmann
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+import { createPublicKey, createVerify, KeyObject } from 'crypto'
+
+const ALGORITHM = 'RSA-SHA1'
+
+export class IABVerifier {
+ private readonly publicKey: KeyObject
+
+ constructor(publicKeyString: string) {
+ this.publicKey = createPublicKey({
+ key: Buffer.from(publicKeyString, 'base64'),
+ format: 'der',
+ type: 'spki'
+ })
+ }
+
+ verifyReceipt(signedData: string, signature: string) {
+ const verifier = createVerify(ALGORITHM)
+
+ verifier.update(signedData)
+
+ return verifier.verify(this.publicKey, signature, 'base64')
+ }
+}
diff --git a/src/function/purchase/verification.ts b/src/function/purchase/verification.ts
index ed03c27..5ba62a2 100644
--- a/src/function/purchase/verification.ts
+++ b/src/function/purchase/verification.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,20 +15,18 @@
* along with this program. If not, see .
*/
-const IABVerifier: new (publicKey: string) => {
- verifyReceipt: (data: string, signature: string) => boolean
-} = require('iab_verifier')
+import { IABVerifier } from './iab_verifierr'
export const googlePlayPublicKey = process.env.GOOGLE_PLAY_PUBLIC_KEY || ''
-const verifier = new IABVerifier(googlePlayPublicKey)
+const verifier = googlePlayPublicKey !== '' ? new IABVerifier(googlePlayPublicKey) : null
-export const areGooglePlayPaymentsPossible = !!googlePlayPublicKey
+export const areGooglePlayPaymentsPossible = !!verifier
export const isGooglePlayPurchaseSignatureValid = ({ receipt, signature }: {
receipt: string
signature: string
}) => {
- if (googlePlayPublicKey) {
+ if (verifier) {
return verifier.verifyReceipt(receipt, signature)
} else {
return false
diff --git a/src/function/sync/apply-actions/cache.ts b/src/function/sync/apply-actions/cache.ts
index 8d47299..fcf9555 100644
--- a/src/function/sync/apply-actions/cache.ts
+++ b/src/function/sync/apply-actions/cache.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -27,11 +27,12 @@ import { InvalidChildActionIntegrityValue } from './exception/integrity'
export class Cache {
readonly familyId: string
+ readonly deviceId: string
readonly hasFullVersion: boolean
transaction: Sequelize.Transaction
readonly database: Database
readonly connectedDevicesManager: VisibleConnectedDevicesManager
- private shouldTriggerFullSync = false
+ private requireSenderDoFullSync = false
categoriesWithModifiedApps = new Set()
categoriesWithModifiedBaseData = new Set()
@@ -39,27 +40,40 @@ export class Cache {
categoriesWithModifiedUsedTimes = new Set()
categoriesWithModifiedTasks = new Set()
- devicesWithModifiedInstalledApps = new Set()
devicesWithModifiedShowDeviceConnected = new Map()
invalidiateUserList = false
invalidiateDeviceList = false
- areChangesImportant = false
+ invalidateU2fList = false
+ triggeredSyncLevel: 0 | 1 | 2 = 0 // 0 = no, 1 = unimportant, 2 = important
+ targetedTriggeredSyncLevels = new Map()
- constructor ({ familyId, hasFullVersion, database, transaction, connectedDevicesManager }: {
+ constructor ({ familyId, deviceId, hasFullVersion, database, transaction, connectedDevicesManager }: {
familyId: string
+ deviceId: string
hasFullVersion: boolean
database: Database
transaction: Sequelize.Transaction
connectedDevicesManager: VisibleConnectedDevicesManager
}) {
this.familyId = familyId
+ this.deviceId = deviceId
this.hasFullVersion = hasFullVersion || config.alwaysPro
this.database = database
this.transaction = transaction
this.connectedDevicesManager = connectedDevicesManager
}
+ incrementTriggeredSyncLevel(newLevel: 1 | 2) {
+ if (newLevel > this.triggeredSyncLevel) this.triggeredSyncLevel = newLevel
+ }
+
+ incrementTargetedTriggeredSyncLevel(deviceId: string, newLevel: 1 | 2) {
+ const oldLevel = this.targetedTriggeredSyncLevels.get(deviceId) || 0
+
+ if (newLevel > oldLevel) this.targetedTriggeredSyncLevels.set(deviceId, newLevel)
+ }
+
async subtransaction (callback: () => Promise): Promise {
const oldTransaction = this.transaction
@@ -140,8 +154,8 @@ export class Cache {
return !!userEntry
})
- shouldDoFullSync = () => this.shouldTriggerFullSync
- requireFullSync: () => void = () => this.shouldTriggerFullSync = true
+ isSenderDoFullSyncTrue = () => this.requireSenderDoFullSync
+ requireSenderFullSync: () => void = () => this.requireSenderDoFullSync = true
async saveModifiedVersionNumbers () {
const { database, transaction, familyId } = this
@@ -226,22 +240,6 @@ export class Cache {
this.categoriesWithModifiedUsedTimes.clear()
}
- if (this.devicesWithModifiedInstalledApps.size > 0) {
- await database.device.update({
- installedAppsVersion: generateVersionId()
- }, {
- where: {
- familyId,
- deviceId: {
- [Sequelize.Op.in]: setToList(this.devicesWithModifiedInstalledApps)
- }
- },
- transaction
- })
-
- this.devicesWithModifiedInstalledApps.clear()
- }
-
if (this.invalidiateUserList) {
await database.family.update({
userListVersion: generateVersionId()
@@ -268,6 +266,19 @@ export class Cache {
this.invalidiateDeviceList = false
}
+ if (this.invalidateU2fList) {
+ await database.family.update({
+ u2fKeysVersion: generateVersionId()
+ }, {
+ where: {
+ familyId: this.familyId
+ },
+ transaction
+ })
+
+ this.invalidateU2fList = false
+ }
+
this.devicesWithModifiedShowDeviceConnected.forEach((showDeviceConnected, deviceId) => {
this.connectedDevicesManager.notifyShareConnectedChanged({
familyId: this.familyId,
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/addinstalledapps.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/addinstalledapps.ts
deleted file mode 100644
index 013b27e..0000000
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/addinstalledapps.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import * as Sequelize from 'sequelize'
-import { AddInstalledAppsAction } from '../../../../action'
-import { AppAttributes, maxPackageNameLength } from '../../../../database/app'
-import { Cache } from '../cache'
-import { ApplyActionException } from '../exception'
-
-export async function dispatchAddInstalledApps ({ deviceId, action, cache }: {
- deviceId: string
- action: AddInstalledAppsAction
- cache: Cache
-}) {
- action.apps.forEach((app) => {
- if (app.packageName.length > maxPackageNameLength) {
- throw new ApplyActionException({
- staticMessage: 'package name too long',
- dynamicMessage: 'package name too long: ' + app.packageName
- })
- }
- })
-
- await cache.database.app.destroy({
- where: {
- familyId: cache.familyId,
- deviceId,
- packageName: {
- [Sequelize.Op.in]: action.apps.map((app) => app.packageName)
- }
- },
- transaction: cache.transaction
- })
-
- await cache.database.app.bulkCreate(
- action.apps.map((app): AppAttributes => ({
- familyId: cache.familyId,
- deviceId,
- packageName: app.packageName,
- title: app.title,
- isLaunchable: app.isLaunchable,
- recommendation: app.recommendation
- })),
- { transaction: cache.transaction }
- )
-
- cache.devicesWithModifiedInstalledApps.add(deviceId)
-}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/addusedtime.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/addusedtime.ts
index 3370b19..3f3be9f 100644
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/addusedtime.ts
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/addusedtime.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,10 +15,10 @@
* along with this program. If not, see .
*/
-import * as Sequelize from 'sequelize'
import { AddUsedTimeAction } from '../../../../action'
import { MinuteOfDay } from '../../../../util/minuteofday'
import { Cache } from '../cache'
+import { IllegalStateException } from '../exception/illegal-state'
import { MissingCategoryException } from '../exception/missing-item'
export const getRoundedTimestamp = () => {
@@ -65,17 +65,10 @@ export async function dispatchAddUsedTime ({ action, cache }: {
currentExtraTime: number
}) => {
if (action.timeToAdd !== 0) {
- const maxOperator = cache.database.dialect === 'sqlite' ? 'MAX' : 'GREATEST'
- const minOperator = cache.database.dialect === 'sqlite' ? 'MIN' : 'LEAST'
-
- // try to update first
- const [updatedRows] = await cache.database.usedTime.update({
- usedTime: Sequelize.literal(`${maxOperator}(0, ${minOperator}(usedTime + ${action.timeToAdd}, ${dayLengthInMs}))`) as any,
- lastUpdate: roundedTimestamp
- }, {
+ const oldItem = await cache.database.usedTime.findOne({
where: {
familyId: cache.familyId,
- categoryId: categoryId,
+ categoryId: action.categoryId,
dayOfEpoch: action.dayOfEpoch,
startMinuteOfDay: MinuteOfDay.MIN,
endMinuteOfDay: MinuteOfDay.MAX
@@ -83,13 +76,38 @@ export async function dispatchAddUsedTime ({ action, cache }: {
transaction: cache.transaction
})
- // otherwise create
- if (updatedRows === 0) {
+ if (oldItem) {
+ const oldUsedTime = oldItem.usedTime
+ const newUsedTime = Math.max(0, Math.min(oldUsedTime + action.timeToAdd, dayLengthInMs))
+
+ const oldLastUpdate = parseInt(oldItem.lastUpdate, 10)
+ const newLastUpdate = parseInt(roundedTimestamp, 10)
+
+ if (oldUsedTime !== newUsedTime || oldLastUpdate !== newLastUpdate) {
+ const [updatedRows] = await cache.database.usedTime.update({
+ usedTime: newUsedTime,
+ lastUpdate: newLastUpdate.toString(10)
+ }, {
+ where: {
+ familyId: cache.familyId,
+ categoryId: action.categoryId,
+ dayOfEpoch: action.dayOfEpoch,
+ startMinuteOfDay: MinuteOfDay.MIN,
+ endMinuteOfDay: MinuteOfDay.MAX
+ },
+ transaction: cache.transaction
+ })
+
+ if (updatedRows === 0) {
+ throw new IllegalStateException({ staticMessage: 'could not update fetched row' })
+ }
+ }
+ } else {
await cache.database.usedTime.create({
familyId: cache.familyId,
- categoryId: categoryId,
+ categoryId: action.categoryId,
dayOfEpoch: action.dayOfEpoch,
- usedTime: Math.min(action.timeToAdd, dayLengthInMs),
+ usedTime: Math.max(0, Math.min(action.timeToAdd, dayLengthInMs)),
lastUpdate: roundedTimestamp,
startMinuteOfDay: MinuteOfDay.MIN,
endMinuteOfDay: MinuteOfDay.MAX
@@ -138,4 +156,6 @@ export async function dispatchAddUsedTime ({ action, cache }: {
})
}
}
+
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/addusedtime2.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/addusedtime2.ts
index a5854ab..5de01be 100644
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/addusedtime2.ts
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/addusedtime2.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -20,9 +20,11 @@ import { AddUsedTimeActionVersion2 } from '../../../../action'
import { EventHandler } from '../../../../monitoring/eventhandler'
import { MinuteOfDay } from '../../../../util/minuteofday'
import { Cache } from '../cache'
-import { SourceDeviceNotFoundException } from '../exception/illegal-state'
+import { IllegalStateException, SourceDeviceNotFoundException } from '../exception/illegal-state'
import { getRoundedTimestamp as getRoundedTimestampForUsedTime } from './addusedtime'
+const tolerance = 5 * 1000 // 5 seconds
+
export const getRoundedTimestampForSessionDuration = () => {
const now = Date.now()
@@ -73,7 +75,7 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
// verify that the category exists
if (!categoryEntryUnsafe) {
eventHandler.countEvent('add used time category to add time for not found')
- cache.requireFullSync()
+ cache.requireSenderFullSync()
continue
}
@@ -87,19 +89,12 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
addUsedTimeForADifferentUserThanTheCurrentUserOfTheDevice = true
}
- // tslint:disable-next-line:no-inner-declarations
+ // eslint-disable-next-line no-inner-declarations
async function handle (start: number, end: number) {
const lengthInMinutes = (end - start) + 1
const lengthInMs = lengthInMinutes * 1000 * 60
- const maxOperator = cache.database.dialect === 'sqlite' ? 'MAX' : 'GREATEST'
- const minOperator = cache.database.dialect === 'sqlite' ? 'MIN' : 'LEAST'
-
- // try to update first
- const [updatedRows] = await cache.database.usedTime.update({
- usedTime: Sequelize.literal(`${maxOperator}(0, ${minOperator}(usedTime + ${item.timeToAdd}, ${lengthInMs}))`) as any,
- lastUpdate: roundedTimestampForUsedTime
- }, {
+ const oldItem = await cache.database.usedTime.findOne({
where: {
familyId: cache.familyId,
categoryId: item.categoryId,
@@ -110,13 +105,59 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
transaction: cache.transaction
})
- // otherwise create
- if (updatedRows === 0) {
+ if (oldItem) {
+ const oldUsedTime = oldItem.usedTime
+ const newUsedTime = Math.max(0, Math.min(oldUsedTime + item.timeToAdd, lengthInMs))
+
+ const oldLastUpdate = parseInt(oldItem.lastUpdate, 10)
+ const newLastUpdate = parseInt(roundedTimestampForUsedTime, 10)
+
+ if (oldUsedTime !== newUsedTime || oldLastUpdate !== newLastUpdate) {
+ const [updatedRows] = await cache.database.usedTime.update({
+ usedTime: newUsedTime,
+ lastUpdate: newLastUpdate.toString(10)
+ }, {
+ where: {
+ familyId: cache.familyId,
+ categoryId: item.categoryId,
+ dayOfEpoch: action.dayOfEpoch,
+ startMinuteOfDay: start,
+ endMinuteOfDay: end
+ },
+ transaction: cache.transaction
+ })
+
+ if (updatedRows === 0) {
+ throw new IllegalStateException({ staticMessage: 'could not update fetched row' })
+ }
+ }
+ } else {
+ const oldTime: number | null = await cache.database.usedTime.aggregate(
+ 'usedTime',
+ 'MAX',
+ {
+ where: {
+ familyId: cache.familyId,
+ categoryId: item.categoryId,
+ dayOfEpoch: action.dayOfEpoch,
+ startMinuteOfDay: {
+ [Sequelize.Op.gte]: start
+ },
+ endMinuteOfDay: {
+ [Sequelize.Op.lte]: end
+ }
+ },
+ transaction: cache.transaction
+ }
+ ) || 0
+
+ if (oldTime !== null && typeof oldTime !== 'number') throw new Error()
+
await cache.database.usedTime.create({
familyId: cache.familyId,
categoryId: item.categoryId,
dayOfEpoch: action.dayOfEpoch,
- usedTime: Math.min(item.timeToAdd, lengthInMs),
+ usedTime: Math.max(0, Math.min(oldTime + item.timeToAdd, lengthInMs)),
lastUpdate: roundedTimestampForUsedTime,
startMinuteOfDay: start,
endMinuteOfDay: end
@@ -151,6 +192,39 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
transaction: cache.transaction
})
+ const oldDuration: () => Promise = async () => {
+ const fittingDurationItems = await cache.database.sessionDuration.findAll({
+ where: {
+ familyId: cache.familyId,
+ categoryId: item.categoryId,
+ startMinuteOfDay: {
+ [Sequelize.Op.gte]: limit.start
+ },
+ endMinuteOfDay: {
+ [Sequelize.Op.lte]: limit.end
+ },
+ maxSessionDuration: {
+ [Sequelize.Op.gte]: limit.duration
+ },
+ sessionPauseDuration: {
+ [Sequelize.Op.lte]: limit.pause
+ }
+ },
+ transaction: cache.transaction
+ })
+
+ const fittingDurationItemsLastUsageFiltered =
+ hasTrustedTimestamp ?
+ fittingDurationItems.filter((it) => {
+ action.trustedTimestamp - item.timeToAdd <=
+ parseInt(it.lastUsage, 10) + it.sessionPauseDuration - tolerance
+ }) : fittingDurationItems
+
+ return fittingDurationItemsLastUsageFiltered
+ .map((it) => it.lastSessionDuration)
+ .reduce((a, b) => Math.max(a, b), 0)
+ }
+
if (oldItem) {
let extendSession: boolean
@@ -171,18 +245,19 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
* Due to this, a session is reset if it would be over in a few seconds, too.
*/
- const tolerance = 5 * 1000 // 5 seconds
const timeWhenStartingCurrentUsage = action.trustedTimestamp - item.timeToAdd
const nextSessionStart = parseInt(oldItem.lastUsage, 10) + oldItem.sessionPauseDuration - tolerance
extendSession = timeWhenStartingCurrentUsage <= nextSessionStart
}
- oldItem.lastSessionDuration = extendSession ? oldItem.lastSessionDuration + item.timeToAdd : item.timeToAdd
+ oldItem.lastSessionDuration = extendSession ? oldItem.lastSessionDuration + item.timeToAdd : await oldDuration() + item.timeToAdd
oldItem.roundedLastUpdate = roundedTimestampForSessionDuration
if (hasTrustedTimestamp) {
- oldItem.lastUsage = action.trustedTimestamp.toString(10)
+ if (parseInt(oldItem.lastUsage, 10) < action.trustedTimestamp) {
+ oldItem.lastUsage = action.trustedTimestamp.toString(10)
+ }
}
await oldItem.save({ transaction: cache.transaction })
@@ -195,8 +270,8 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
startMinuteOfDay: limit.start,
endMinuteOfDay: limit.end,
// end of primary key
- lastUsage: action.trustedTimestamp,
- lastSessionDuration: item.timeToAdd,
+ lastUsage: action.trustedTimestamp.toString(10),
+ lastSessionDuration: await oldDuration() + item.timeToAdd,
roundedLastUpdate: roundedTimestampForSessionDuration
}, { transaction: cache.transaction })
}
@@ -228,9 +303,11 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
// As it should occur not too often, a full sync should be no problem.
// To keep an eye on it, it is counted.
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
eventHandler.countEvent('add used time for a different user than the current user of the device')
}
}
+
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/removeinstalledapps.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/finishkeyrequest.ts
similarity index 65%
rename from src/function/sync/apply-actions/dispatch-app-logic-action/removeinstalledapps.ts
rename to src/function/sync/apply-actions/dispatch-app-logic-action/finishkeyrequest.ts
index 03768a3..74b3129 100644
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/removeinstalledapps.ts
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/finishkeyrequest.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,25 +15,22 @@
* along with this program. If not, see .
*/
-import * as Sequelize from 'sequelize'
-import { RemoveInstalledAppsAction } from '../../../../action'
+import { FinishKeyRequestAction } from '../../../../action'
import { Cache } from '../cache'
-export async function dispatchRemoveInstalledApps ({ deviceId, action, cache }: {
+export async function dispatchFinishKeyRequestAction ({ action, cache, deviceId }: {
deviceId: string
- action: RemoveInstalledAppsAction
+ action: FinishKeyRequestAction
cache: Cache
}) {
- await cache.database.app.destroy({
+ await cache.database.keyRequest.destroy({
where: {
familyId: cache.familyId,
- deviceId,
- packageName: {
- [Sequelize.Op.in]: action.packageNames
- }
+ senderDeviceId: deviceId,
+ senderSequenceNumber: action.deviceSequenceNumber.toString(10)
},
transaction: cache.transaction
})
- cache.devicesWithModifiedInstalledApps.add(deviceId)
+ // no sync triggered
}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/forcesync.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/forcesync.ts
index 00ea17b..ada5dc1 100644
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/forcesync.ts
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/forcesync.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -23,5 +23,5 @@ export async function dispatchForceSyncAction ({ cache }: {
action: ForceSyncAction
cache: Cache
}) {
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/index.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/index.ts
index ebef50c..f535247 100644
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/index.ts
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -20,27 +20,34 @@ import {
AddUsedTimeAction,
AddUsedTimeActionVersion2,
AppLogicAction,
+ FinishKeyRequestAction,
ForceSyncAction,
MarkTaskPendingAction,
+ ReplyToKeyRequestAction,
RemoveInstalledAppsAction,
+ SendKeyRequestAction,
SignOutAtDeviceAction,
TriedDisablingDeviceAdminAction,
UpdateAppActivitiesAction,
- UpdateDeviceStatusAction
+ UpdateDeviceStatusAction,
+ UpdateInstalledAppsAction,
+ UploadDevicePublicKeyAction
} from '../../../../action'
import { EventHandler } from '../../../../monitoring/eventhandler'
import { Cache } from '../cache'
import { ActionObjectTypeNotHandledException } from '../exception/illegal-state'
-import { dispatchAddInstalledApps } from './addinstalledapps'
import { dispatchAddUsedTime } from './addusedtime'
import { dispatchAddUsedTimeVersion2 } from './addusedtime2'
+import { dispatchFinishKeyRequestAction } from './finishkeyrequest'
import { dispatchForceSyncAction } from './forcesync'
import { dispatchMarkTaskPendingAction } from './marktaskpendingaction'
-import { dispatchRemoveInstalledApps } from './removeinstalledapps'
+import { dispatchReplyToKeyRequestAction } from './replytokeyrequest'
+import { dispatchSendKeyRequestAction } from './sendkeyrequest'
import { dispatchSignOutAtDevice } from './signoutatdevice'
import { dispatchTriedDisablingDeviceAdmin } from './trieddisablingdeviceadmin'
-import { dispatchUpdateAppActivities } from './updateappactivities'
import { dispatchUpdateDeviceStatus } from './updatedevicestatus'
+import { dispatchUpdateInstalledApps } from './updateinstalledapps'
+import { dispatchUploadDevicePublicKeyAction } from './uploaddevicepublickey'
export const dispatchAppLogicAction = async ({ action, deviceId, cache, eventHandler }: {
action: AppLogicAction
@@ -49,25 +56,35 @@ export const dispatchAppLogicAction = async ({ action, deviceId, cache, eventHan
eventHandler: EventHandler
}) => {
if (action instanceof AddInstalledAppsAction) {
- await dispatchAddInstalledApps({ deviceId, action, cache })
+ // do nothing
} else if (action instanceof AddUsedTimeAction) {
await dispatchAddUsedTime({ deviceId, action, cache })
} else if (action instanceof AddUsedTimeActionVersion2) {
await dispatchAddUsedTimeVersion2({ deviceId, action, cache, eventHandler })
+ } else if (action instanceof FinishKeyRequestAction) {
+ await dispatchFinishKeyRequestAction({ deviceId, action, cache })
} else if (action instanceof ForceSyncAction) {
await dispatchForceSyncAction({ deviceId, action, cache })
} else if (action instanceof MarkTaskPendingAction) {
await dispatchMarkTaskPendingAction({ deviceId, action, cache })
+ } else if (action instanceof ReplyToKeyRequestAction) {
+ await dispatchReplyToKeyRequestAction({ deviceId, action, cache, eventHandler })
} else if (action instanceof RemoveInstalledAppsAction) {
- await dispatchRemoveInstalledApps({ deviceId, action, cache })
+ // do nothing
+ } else if (action instanceof SendKeyRequestAction) {
+ await dispatchSendKeyRequestAction({ deviceId, action, cache })
} else if (action instanceof SignOutAtDeviceAction) {
await dispatchSignOutAtDevice({ deviceId, action, cache })
} else if (action instanceof UpdateDeviceStatusAction) {
await dispatchUpdateDeviceStatus({ deviceId, action, cache })
} else if (action instanceof UpdateAppActivitiesAction) {
- await dispatchUpdateAppActivities({ deviceId, action, cache })
+ // do nothing
} else if (action instanceof TriedDisablingDeviceAdminAction) {
await dispatchTriedDisablingDeviceAdmin({ deviceId, action, cache })
+ } else if (action instanceof UpdateInstalledAppsAction) {
+ await dispatchUpdateInstalledApps({ deviceId, action, cache })
+ } else if (action instanceof UploadDevicePublicKeyAction) {
+ await dispatchUploadDevicePublicKeyAction({ deviceId, action, cache, eventHandler })
} else {
throw new ActionObjectTypeNotHandledException()
}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/marktaskpendingaction.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/marktaskpendingaction.ts
index cd6e334..5533589 100644
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/marktaskpendingaction.ts
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/marktaskpendingaction.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,8 +16,9 @@
*/
import { MarkTaskPendingAction } from '../../../../action'
+import { sendTaskDoneMails } from '../../../warningmail/taskdone'
import { Cache } from '../cache'
-import { IllegalStateException, SourceDeviceNotFoundException } from '../exception/illegal-state'
+import { IllegalStateException, SourceDeviceNotFoundException, SourceUserNotFoundException } from '../exception/illegal-state'
import { MissingTaskException } from '../exception/missing-item'
export async function dispatchMarkTaskPendingAction ({ action, cache, deviceId }: {
@@ -31,14 +32,15 @@ export async function dispatchMarkTaskPendingAction ({ action, cache, deviceId }
taskId: action.taskId
},
transaction: cache.transaction,
- attributes: ['categoryId', 'pendingRequest']
+ attributes: ['categoryId', 'pendingRequest', 'taskTitle']
})
if (taskInfoUnsafe === null) throw new MissingTaskException()
const taskInfo = {
categoryId: taskInfoUnsafe.categoryId,
- pendingRequest: taskInfoUnsafe.pendingRequest
+ pendingRequest: taskInfoUnsafe.pendingRequest,
+ taskTitle: taskInfoUnsafe.taskTitle
}
if (taskInfo.pendingRequest !== 0) return // review already requested
@@ -75,7 +77,20 @@ export async function dispatchMarkTaskPendingAction ({ action, cache, deviceId }
throw new IllegalStateException({ staticMessage: 'Can not mark task pending for other user than the current user' })
}
- await cache.database.childTask.update({ pendingRequest: true }, {
+ const childInfoUnsafe = await cache.database.user.findOne({
+ where: {
+ familyId: cache.familyId,
+ userId: categoryInfo.childId
+ },
+ attributes: ['name'],
+ transaction: cache.transaction
+ })
+
+ if (childInfoUnsafe === null) throw new SourceUserNotFoundException()
+
+ const childInfo = { name: childInfoUnsafe.name }
+
+ await cache.database.childTask.update({ pendingRequest: 1 }, {
where: {
familyId: cache.familyId,
taskId: action.taskId
@@ -84,4 +99,13 @@ export async function dispatchMarkTaskPendingAction ({ action, cache, deviceId }
})
cache.categoriesWithModifiedTasks.add(taskInfo.categoryId)
+ cache.incrementTriggeredSyncLevel(1) // parents are not faster reachable
+
+ await sendTaskDoneMails({
+ database: cache.database,
+ transaction: cache.transaction,
+ familyId: cache.familyId,
+ childName: childInfo.name,
+ taskTitle: taskInfo.taskTitle
+ })
}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/replytokeyrequest.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/replytokeyrequest.ts
new file mode 100644
index 0000000..33f522f
--- /dev/null
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/replytokeyrequest.ts
@@ -0,0 +1,109 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { ReplyToKeyRequestAction } from '../../../../action'
+import { Cache } from '../cache'
+import { EventHandler } from '../../../../monitoring/eventhandler'
+import { IllegalStateException } from '../exception/illegal-state'
+
+export async function dispatchReplyToKeyRequestAction ({ deviceId, action, cache, eventHandler }: {
+ deviceId: string
+ action: ReplyToKeyRequestAction
+ cache: Cache
+ eventHandler: EventHandler
+}) {
+ const requestUnsafe = await cache.database.keyRequest.findOne({
+ where: {
+ familyId: cache.familyId,
+ serverSequenceNumber: action.requestServerSequenceNumber.toString(10)
+ },
+ attributes: ['senderDeviceId', 'senderSequenceNumber'],
+ transaction: cache.transaction
+ })
+
+ if (!requestUnsafe) {
+ eventHandler.countEvent('dispatchReplyToKeyRequestAction:request does not exists (anymore)')
+
+ return
+ }
+
+ const request = {
+ senderDeviceId: requestUnsafe.senderDeviceId,
+ senderSequenceNumber: requestUnsafe.senderSequenceNumber
+ }
+
+ const oldReplyCounter = await cache.database.keyResponse.count({
+ where: {
+ familyId: cache.familyId,
+ receiverDeviceId: request.senderDeviceId,
+ requestServerSequenceNumber: action.requestServerSequenceNumber.toString(10),
+ senderDeviceId: deviceId
+ },
+ transaction: cache.transaction
+ })
+
+ if (oldReplyCounter !== 0) {
+ eventHandler.countEvent('dispatchReplyToKeyRequestAction:got duplicate reply which was ignored')
+
+ return
+ }
+
+ const deviceEntryUnsafe = await cache.database.device.findOne({
+ where: {
+ familyId: cache.familyId,
+ deviceId: request.senderDeviceId
+ },
+ transaction: cache.transaction,
+ attributes: ['nextKeyReplySequenceNumber']
+ })
+
+ if (!deviceEntryUnsafe) {
+ throw new IllegalStateException({
+ staticMessage: 'target device entry not found'
+ })
+ }
+
+ const deviceEntry = {
+ nextKeyReplySequenceNumber: deviceEntryUnsafe.nextKeyReplySequenceNumber
+ }
+
+ await cache.database.device.update({
+ nextKeyReplySequenceNumber: (parseInt(deviceEntry.nextKeyReplySequenceNumber) + 1).toString(10)
+ }, {
+ where: {
+ familyId: cache.familyId,
+ deviceId: request.senderDeviceId
+ },
+ transaction: cache.transaction
+ })
+
+ await cache.database.keyResponse.create({
+ familyId: cache.familyId,
+ receiverDeviceId: request.senderDeviceId,
+ requestServerSequenceNumber: action.requestServerSequenceNumber.toString(10),
+ senderDeviceId: deviceId,
+ replyServerSequenceNumber: deviceEntry.nextKeyReplySequenceNumber,
+ requestClientSequenceNumber: requestUnsafe.senderSequenceNumber,
+ tempKey: action.tempKey,
+ encryptedKey: action.encryptedKey,
+ signature: action.signature
+ }, {
+ transaction: cache.transaction
+ })
+
+ cache.incrementTargetedTriggeredSyncLevel(request.senderDeviceId, 2)
+}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/sendkeyrequest.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/sendkeyrequest.ts
new file mode 100644
index 0000000..a79b1f2
--- /dev/null
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/sendkeyrequest.ts
@@ -0,0 +1,76 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { SendKeyRequestAction } from '../../../../action'
+import { Cache } from '../cache'
+import { SourceFamilyNotFoundException } from '../exception/illegal-state'
+
+export async function dispatchSendKeyRequestAction ({ action, cache, deviceId }: {
+ deviceId: string
+ action: SendKeyRequestAction
+ cache: Cache
+}) {
+ const familyEntryUnsafe = await cache.database.family.findOne({
+ where: {
+ familyId: cache.familyId
+ },
+ transaction: cache.transaction,
+ attributes: ['nextServerKeyRequestSeq']
+ })
+
+ if (!familyEntryUnsafe) {
+ throw new SourceFamilyNotFoundException()
+ }
+
+ const serverSequenceNumber = familyEntryUnsafe.nextServerKeyRequestSeq
+
+ await cache.database.family.update({
+ nextServerKeyRequestSeq: (parseInt(serverSequenceNumber, 10) + 1).toString(10)
+ }, {
+ where: {
+ familyId: cache.familyId
+ },
+ transaction: cache.transaction
+ })
+
+ await cache.database.keyRequest.destroy({
+ where: {
+ familyId: cache.familyId,
+ senderDeviceId: deviceId,
+ type: action.type,
+ deviceId: action.deviceId || null,
+ categoryId: action.categoryId || null
+ },
+ transaction: cache.transaction
+ })
+
+ await cache.database.keyRequest.create({
+ familyId: cache.familyId,
+ serverSequenceNumber: serverSequenceNumber,
+ senderDeviceId: deviceId,
+ senderSequenceNumber: action.deviceSequenceNumber.toString(10),
+ deviceId: action.deviceId || null,
+ categoryId: action.categoryId || null,
+ type: action.type,
+ tempKey: action.tempKey,
+ signature: action.signature
+ }, {
+ transaction: cache.transaction
+ })
+
+ cache.incrementTriggeredSyncLevel(2)
+}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/signoutatdevice.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/signoutatdevice.ts
index a15684c..d300581 100644
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/signoutatdevice.ts
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/signoutatdevice.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -57,4 +57,6 @@ export async function dispatchSignOutAtDevice ({ deviceId, cache }: {
})
})
}
+
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/trieddisablingdeviceadmin.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/trieddisablingdeviceadmin.ts
index a376abd..dfde422 100644
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/trieddisablingdeviceadmin.ts
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/trieddisablingdeviceadmin.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -46,7 +46,7 @@ export async function dispatchTriedDisablingDeviceAdmin ({ deviceId, cache }: {
await deviceEntry.save({ transaction: cache.transaction })
cache.invalidiateDeviceList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(1)
}
if (!hadManipulationBefore) {
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/updateappactivities.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/updateappactivities.ts
deleted file mode 100644
index 82ea302..0000000
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/updateappactivities.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import { chunk } from 'lodash'
-import * as Sequelize from 'sequelize'
-import { UpdateAppActivitiesAction } from '../../../../action'
-import { AppActivityAttributes, maxActivityNameLength, maxPackageNameLength } from '../../../../database/appactivity'
-import { Cache } from '../cache'
-import { ApplyActionException } from '../exception'
-
-export async function dispatchUpdateAppActivities ({ deviceId, action, cache }: {
- deviceId: string
- action: UpdateAppActivitiesAction
- cache: Cache
-}) {
- action.updatedOrAdded.forEach((app) => {
- if (app.packageName.length > maxPackageNameLength) {
- throw new ApplyActionException({
- staticMessage: 'package name too long',
- dynamicMessage: 'package name too long: ' + app.packageName
- })
- }
-
- if (app.activityName.length > maxActivityNameLength) {
- throw new ApplyActionException({
- staticMessage: 'activity name too long',
- dynamicMessage: 'activity name too long: ' + app.activityName
- })
- }
- })
-
- if (action.updatedOrAdded.length > 0) {
- const chuncks = chunk(action.updatedOrAdded, 500)
-
- for (const items of chuncks) {
- await cache.database.appActivity.destroy({
- where: {
- familyId: cache.familyId,
- deviceId,
- [Sequelize.Op.or]: (
- items.map((item) => ({
- packageName: item.packageName,
- activityName: item.activityName
- }))
- )
- },
- transaction: cache.transaction
- })
- }
-
- await cache.database.appActivity.bulkCreate(
- action.updatedOrAdded.map((item): AppActivityAttributes => ({
- familyId: cache.familyId,
- deviceId,
- packageName: item.packageName,
- activityName: item.activityName,
- title: item.title
- })),
- { transaction: cache.transaction }
- )
- }
-
- if (action.removed.length > 0) {
- const chunks = chunk(action.removed, 500)
-
- for (const items of chunks) {
- await cache.database.appActivity.destroy({
- where: {
- familyId: cache.familyId,
- deviceId,
- [Sequelize.Op.or]: (
- items.map((item) => ({
- packageName: item.packageName,
- activityName: item.activityName
- }))
- )
- },
- transaction: cache.transaction
- })
- }
- }
-
- cache.devicesWithModifiedInstalledApps.add(deviceId)
-}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/updatedevicestatus.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/updatedevicestatus.ts
index 39d8290..070ac7c 100644
--- a/src/function/sync/apply-actions/dispatch-app-logic-action/updatedevicestatus.ts
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/updatedevicestatus.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,7 +16,7 @@
*/
import { UpdateDeviceStatusAction } from '../../../../action'
-import { DeviceHadManipulationFlags, hasDeviceManipulation } from '../../../../database/device'
+import { DeviceHadManipulationFlags, DeviceManipulationFlags, hasDeviceManipulation } from '../../../../database/device'
import { newPermissionStatusValues } from '../../../../model/newpermissionstatus'
import { protetionLevels } from '../../../../model/protectionlevel'
import { runtimePermissionStatusValues } from '../../../../model/runtimepermissionstatus'
@@ -155,6 +155,26 @@ export async function dispatchUpdateDeviceStatus ({ deviceId, action, cache }: {
}
}
+ if (action.platformType !== undefined) {
+ if (action.platformType !== deviceEntry.platformType) {
+ deviceEntry.platformType = action.platformType
+ }
+ }
+
+ if (action.platformLevel !== undefined) {
+ if (action.platformLevel !== deviceEntry.platformLevel) {
+ deviceEntry.platformLevel = action.platformLevel
+ }
+ }
+
+ {
+ const effectiveManipulationFlags = action.addedManipulationFlags & DeviceManipulationFlags.ALL
+
+ if (effectiveManipulationFlags !== 0) {
+ deviceEntry.manipulationFlags = deviceEntry.manipulationFlags | effectiveManipulationFlags
+ }
+ }
+
await deviceEntry.save({ transaction: cache.transaction })
if (hasDeviceManipulation(deviceEntry)) {
@@ -169,5 +189,5 @@ export async function dispatchUpdateDeviceStatus ({ deviceId, action, cache }: {
}
cache.invalidiateDeviceList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/updateinstalledapps.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/updateinstalledapps.ts
new file mode 100644
index 0000000..fae4520
--- /dev/null
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/updateinstalledapps.ts
@@ -0,0 +1,47 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { UpdateInstalledAppsAction } from '../../../../action'
+import { types } from '../../../../database/encryptedapplist'
+import { generateVersionId } from '../../../../util/token'
+import { Cache } from '../cache'
+
+export async function dispatchUpdateInstalledApps ({ deviceId, action, cache }: {
+ deviceId: string
+ action: UpdateInstalledAppsAction
+ cache: Cache
+}) {
+ async function upsert({ type, data }: { type: number, data: Buffer }) {
+ await cache.database.encryptedAppList.upsert({
+ familyId: cache.familyId,
+ deviceId,
+ type,
+ version: generateVersionId(),
+ data
+ }, { transaction: cache.transaction })
+ }
+
+ if (action.base) {
+ await upsert({ type: types.base, data: action.base })
+ }
+
+ if (action.diff) {
+ await upsert({ type: types.diff, data: action.diff })
+ }
+
+ cache.incrementTriggeredSyncLevel(1)
+}
diff --git a/src/function/sync/apply-actions/dispatch-app-logic-action/uploaddevicepublickey.ts b/src/function/sync/apply-actions/dispatch-app-logic-action/uploaddevicepublickey.ts
new file mode 100644
index 0000000..0ac9b90
--- /dev/null
+++ b/src/function/sync/apply-actions/dispatch-app-logic-action/uploaddevicepublickey.ts
@@ -0,0 +1,51 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { UploadDevicePublicKeyAction } from '../../../../action'
+import { Cache } from '../cache'
+import { EventHandler } from '../../../../monitoring/eventhandler'
+import { SourceDeviceNotFoundException } from '../exception/illegal-state'
+
+export async function dispatchUploadDevicePublicKeyAction ({ deviceId, action, cache, eventHandler }: {
+ deviceId: string
+ action: UploadDevicePublicKeyAction
+ cache: Cache
+ eventHandler: EventHandler
+}) {
+ const deviceEntry = await cache.database.device.findOne({
+ where: {
+ familyId: cache.familyId,
+ deviceId
+ },
+ transaction: cache.transaction
+ })
+
+ if (deviceEntry === null) {
+ throw new SourceDeviceNotFoundException()
+ } else if (deviceEntry.publicKey === null) {
+ deviceEntry.publicKey = action.key
+
+ await deviceEntry.save({ transaction: cache.transaction })
+
+ cache.invalidiateDeviceList = true
+ cache.incrementTriggeredSyncLevel(2)
+ } else if (deviceEntry.publicKey.equals(action.key)) {
+ eventHandler.countEvent('dispatchUploadDevicePublicKeyAction:duplicate action')
+ } else {
+ eventHandler.countEvent('dispatchUploadDevicePublicKeyAction:got new public key for existing device')
+ }
+}
diff --git a/src/function/sync/apply-actions/dispatch-child-action/childchangepassword.ts b/src/function/sync/apply-actions/dispatch-child-action/childchangepassword.ts
index ceecdfe..374d796 100644
--- a/src/function/sync/apply-actions/dispatch-child-action/childchangepassword.ts
+++ b/src/function/sync/apply-actions/dispatch-child-action/childchangepassword.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,10 +15,10 @@
* along with this program. If not, see .
*/
-import * as Sequelize from 'sequelize'
import { ChildChangePasswordAction } from '../../../../action'
import { Cache } from '../cache'
import { SourceUserNotFoundException } from '../exception/illegal-state'
+import { decryptParentPassword } from '../../../dh'
export const dispatchChildChangePassword = async ({ action, childUserId, cache }: {
action: ChildChangePasswordAction
@@ -31,17 +31,18 @@ export const dispatchChildChangePassword = async ({ action, childUserId, cache }
userId: childUserId,
type: 'child'
},
- transaction: cache.transaction,
- lock: Sequelize.Transaction.LOCK.UPDATE
+ transaction: cache.transaction
})
if (!childEntry) {
throw new SourceUserNotFoundException()
}
- childEntry.passwordHash = action.password.hash
- childEntry.secondPasswordSalt = action.password.secondSalt
- childEntry.secondPasswordHash = action.password.secondHash
+ const newPassword = await decryptParentPassword({ cache, password: action.password })
+
+ childEntry.passwordHash = newPassword.hash
+ childEntry.secondPasswordSalt = newPassword.secondSalt
+ childEntry.secondPasswordHash = newPassword.secondHash
await childEntry.save({ transaction: cache.transaction })
@@ -51,5 +52,5 @@ export const dispatchChildChangePassword = async ({ action, childUserId, cache }
}
cache.invalidiateUserList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-child-action/childsignin.ts b/src/function/sync/apply-actions/dispatch-child-action/childsignin.ts
index 9699fb2..1704572 100644
--- a/src/function/sync/apply-actions/dispatch-child-action/childsignin.ts
+++ b/src/function/sync/apply-actions/dispatch-child-action/childsignin.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -71,4 +71,6 @@ export const dispatchChildSignIn = async ({ deviceId, childUserId, cache }: {
cache.invalidiateUserList = true
}
+
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-helper/helper.ts b/src/function/sync/apply-actions/dispatch-helper/helper.ts
index 4de6d25..e21ad53 100644
--- a/src/function/sync/apply-actions/dispatch-helper/helper.ts
+++ b/src/function/sync/apply-actions/dispatch-helper/helper.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -26,7 +26,7 @@ import { parseEncodedAction } from '../parse-encoded-action'
export async function dispatch ({ type, action, validator, parser, applier, eventHandler }: {
type: 'app logic' | 'parent' | 'child'
action: ClientPushChangesRequestAction
- validator: (input: any) => input is T1
+ validator: (input: unknown) => input is T1
parser: (input: T1) => T2
applier: (input: T2) => Promise
eventHandler: EventHandler
diff --git a/src/function/sync/apply-actions/dispatch-helper/parent-action.ts b/src/function/sync/apply-actions/dispatch-helper/parent-action.ts
index c0d8a6e..d293d52 100644
--- a/src/function/sync/apply-actions/dispatch-helper/parent-action.ts
+++ b/src/function/sync/apply-actions/dispatch-helper/parent-action.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -24,14 +24,18 @@ import { Cache } from '../cache'
import { dispatchParentAction as dispatchParentActionInternal } from '../dispatch-parent-action'
import { SourceDeviceNotFoundException } from '../exception/illegal-state'
import { SelfLimitNotPossibleException } from '../exception/self-limit'
+import { AuthenticationMethod } from '../types'
import { dispatch } from './helper'
-export async function dispatchParentAction ({ action, eventHandler, cache, isChildLimitAdding, deviceId }: {
+export async function dispatchParentAction ({
+ action, eventHandler, cache, isChildLimitAdding, deviceId, authentication
+}: {
action: ClientPushChangesRequestAction
cache: Cache
eventHandler: EventHandler
isChildLimitAdding: boolean
deviceId: string
+ authentication: AuthenticationMethod
}) {
return dispatch({
action,
@@ -90,7 +94,8 @@ export async function dispatchParentAction ({ action, eventHandler, cache, isChi
cache,
parentUserId: action.userId,
sourceDeviceId: deviceId,
- fromChildSelfLimitAddChildUserId: deviceUserId
+ fromChildSelfLimitAddChildUserId: deviceUserId,
+ authentication
})
} else {
await dispatchParentActionInternal({
@@ -98,7 +103,8 @@ export async function dispatchParentAction ({ action, eventHandler, cache, isChi
cache,
parentUserId: action.userId,
sourceDeviceId: deviceId,
- fromChildSelfLimitAddChildUserId: null
+ fromChildSelfLimitAddChildUserId: null,
+ authentication
})
}
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/addcategoryapps.ts b/src/function/sync/apply-actions/dispatch-parent-action/addcategoryapps.ts
index 141ce82..e6b8b72 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/addcategoryapps.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/addcategoryapps.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -50,21 +50,21 @@ export async function dispatchAddCategoryApps ({ action, cache, fromChildSelfLim
}
}
- const categoriesOfSameChild = await cache.database.category.findAll({
+ const categoriesOfSameChild = (await cache.database.category.findAll({
where: {
familyId: cache.familyId,
childId
},
attributes: ['categoryId', 'parentCategoryId'],
transaction: cache.transaction
- }).map((item) => ({
+ })).map((item) => ({
categoryId: item.categoryId,
parentCategoryId: item.parentCategoryId
}))
const userCategoryIds = categoriesOfSameChild.map((item) => item.categoryId)
- const oldCategories = await cache.database.categoryApp.findAll({
+ const oldCategories = (await cache.database.categoryApp.findAll({
attributes: [ 'categoryId' ],
group: [ 'categoryId' ],
where: {
@@ -77,9 +77,19 @@ export async function dispatchAddCategoryApps ({ action, cache, fromChildSelfLim
}
},
transaction: cache.transaction
- }).map((item) => item.categoryId)
+ })).map((item) => item.categoryId)
if (fromChildSelfLimitAddChildUserId !== null) {
+ for (let i = 0; i < action.packageNames.length; i++) {
+ const packageName = action.packageNames[i]
+
+ if (packageName.indexOf('@') !== -1) {
+ throw new SelfLimitationException({
+ staticMessage: 'can not do device specific assignments as child'
+ })
+ }
+ }
+
try {
const parentCategoriesOfTargetCategory = getCategoryWithParentCategories(categoriesOfSameChild, action.categoryId)
const userEntryUnsafe = await cache.database.user.findOne({
@@ -179,5 +189,5 @@ export async function dispatchAddCategoryApps ({ action, cache, fromChildSelfLim
oldCategories.forEach((categoryId) => cache.categoriesWithModifiedApps.add(categoryId))
cache.categoriesWithModifiedApps.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/addcategorynetworkid.ts b/src/function/sync/apply-actions/dispatch-parent-action/addcategorynetworkid.ts
index f58b31d..4425600 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/addcategorynetworkid.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/addcategorynetworkid.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -75,5 +75,5 @@ export async function dispatchAddCategoryNetworkId ({ action, cache }: {
}, { transaction: cache.transaction })
cache.categoriesWithModifiedBaseData.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/addu2fkey.ts b/src/function/sync/apply-actions/dispatch-parent-action/addu2fkey.ts
new file mode 100644
index 0000000..0d0a877
--- /dev/null
+++ b/src/function/sync/apply-actions/dispatch-parent-action/addu2fkey.ts
@@ -0,0 +1,49 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { AddParentU2fKeyAction } from '../../../../action'
+import { getU2fKeyId } from '../../../../database/u2fkey'
+import { Cache } from '../cache'
+import { LimitReachedException } from '../exception/limit'
+
+export async function dispatchAddU2f ({ action, cache, parentUserId }: {
+ action: AddParentU2fKeyAction
+ cache: Cache
+ parentUserId: string
+}) {
+ const counter = await cache.database.u2fKey.count({
+ where: {
+ familyId: cache.familyId
+ },
+ transaction: cache.transaction
+ })
+
+ if (counter >= 16) throw new LimitReachedException({ type: 'u2f keys' })
+
+ await cache.database.u2fKey.create({
+ familyId: cache.familyId,
+ keyId: getU2fKeyId({ keyHandle: action.keyHandle, publicKey: action.publicKey }),
+ userId: parentUserId,
+ addedAt: Date.now().toString(10),
+ keyHandle: action.keyHandle,
+ publicKey: action.publicKey,
+ nextCounter: '0'
+ }, { transaction: cache.transaction })
+
+ cache.invalidateU2fList = true
+ cache.incrementTriggeredSyncLevel(1)
+}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/adduser.ts b/src/function/sync/apply-actions/dispatch-parent-action/adduser.ts
index 761a4a4..995a3fa 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/adduser.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/adduser.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,21 +16,27 @@
*/
import { AddUserAction } from '../../../../action'
+import { decryptParentPassword } from '../../../dh'
import { Cache } from '../cache'
export async function dispatchAddUser ({ action, cache }: {
action: AddUserAction
cache: Cache
}) {
+ const password =
+ action.password ?
+ await decryptParentPassword({ cache, password: action.password }) :
+ null
+
await cache.database.user.create({
familyId: cache.familyId,
userId: action.userId,
type: action.userType,
name: action.name,
timeZone: action.timeZone,
- passwordHash: action.password ? action.password.hash : '',
- secondPasswordHash: action.password ? action.password.secondHash : '',
- secondPasswordSalt: action.password ? action.password.secondSalt : '',
+ passwordHash: password ? password.hash : '',
+ secondPasswordHash: password ? password.secondHash : '',
+ secondPasswordSalt: password ? password.secondSalt : '',
mail: '',
disableTimelimitsUntil: '0',
currentDevice: '',
@@ -42,7 +48,7 @@ export async function dispatchAddUser ({ action, cache }: {
}, { transaction: cache.transaction })
cache.invalidiateUserList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(1)
cache.doesUserExist.cache.set(action.userId, true)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/changeparentpassword.ts b/src/function/sync/apply-actions/dispatch-parent-action/changeparentpassword.ts
index 9450531..b419ab9 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/changeparentpassword.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/changeparentpassword.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,7 +15,6 @@
* along with this program. If not, see .
*/
-import * as Sequelize from 'sequelize'
import { ChangeParentPasswordAction, InvalidChangeParentPasswordIntegrityException } from '../../../../action/changeparentpassword'
import { Cache } from '../cache'
import { ApplyActionException } from '../exception/index'
@@ -31,8 +30,7 @@ export async function dispatchChangeParentPassword ({ action, cache }: {
userId: action.parentUserId,
type: 'parent'
},
- transaction: cache.transaction,
- lock: Sequelize.Transaction.LOCK.UPDATE
+ transaction: cache.transaction
})
if (!parentEntry) {
@@ -61,5 +59,5 @@ export async function dispatchChangeParentPassword ({ action, cache }: {
}
cache.invalidiateUserList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/createcategory.ts b/src/function/sync/apply-actions/dispatch-parent-action/createcategory.ts
index 9e573ea..8acf060 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/createcategory.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/createcategory.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -65,7 +65,7 @@ export async function dispatchCreateCategory ({ action, cache, fromChildSelfLimi
title: action.title,
blockedMinutesInWeek: '',
temporarilyBlocked: false,
- temporarilyBlockedEndTime: 0,
+ temporarilyBlockedEndTime: '0',
extraTimeInMillis: 0,
extraTimeDay: -1,
timeLimitRulesVersion: generateVersionId(),
@@ -76,11 +76,15 @@ export async function dispatchCreateCategory ({ action, cache, fromChildSelfLimi
blockAllNotifications: false,
timeWarningFlags: 0,
sort,
- disableLimitsUntil: 0,
- taskListVersion: generateVersionId()
+ disableLimitsUntil: '0',
+ taskListVersion: generateVersionId(),
+ minBatteryCharging: 0,
+ minBatteryMobile: 0,
+ flags: '0',
+ blockNotificationDelay: '0'
}, { transaction: cache.transaction })
// update the cache
cache.doesCategoryExist.cache.set(action.categoryId, true)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/createtimelimitrule.ts b/src/function/sync/apply-actions/dispatch-parent-action/createtimelimitrule.ts
index 9b6eb87..8e98ceb 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/createtimelimitrule.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/createtimelimitrule.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -54,9 +54,10 @@ export async function dispatchCreateTimeLimitRule ({ action, cache, fromChildSel
startMinuteOfDay: action.rule.start,
endMinuteOfDay: action.rule.end,
sessionDurationMilliseconds: action.rule.sessionDurationMilliseconds,
- sessionPauseMilliseconds: action.rule.sessionPauseMilliseconds
+ sessionPauseMilliseconds: action.rule.sessionPauseMilliseconds,
+ perDay: action.rule.perDay ? 1 : 0
}, { transaction: cache.transaction })
cache.categoriesWithModifiedTimeLimitRules.add(action.rule.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/deletecategory.ts b/src/function/sync/apply-actions/dispatch-parent-action/deletecategory.ts
index b9a2a7b..cafce98 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/deletecategory.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/deletecategory.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -80,7 +80,7 @@ export async function dispatchDeleteCategory ({ action, cache }: {
// update the cache
cache.doesCategoryExist.cache.set(action.categoryId, false)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
if (affectedUserRows !== 0) {
cache.invalidiateUserList = true
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/deletechildtaskaction.ts b/src/function/sync/apply-actions/dispatch-parent-action/deletechildtaskaction.ts
index 0ec5f38..f8f5077 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/deletechildtaskaction.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/deletechildtaskaction.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -45,4 +45,5 @@ export async function dispatchDeleteChildTaskAction ({ action, cache }: {
})
cache.categoriesWithModifiedTasks.add(taskInfo.categoryId)
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/deletetimelimitrule.ts b/src/function/sync/apply-actions/dispatch-parent-action/deletetimelimitrule.ts
index e685955..9419b4a 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/deletetimelimitrule.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/deletetimelimitrule.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -38,5 +38,5 @@ export async function dispatchDeleteTimeLimitRule ({ action, cache }: {
await ruleEntry.destroy({ transaction: cache.transaction })
cache.categoriesWithModifiedTimeLimitRules.add(ruleEntry.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/ignoremanipulation.ts b/src/function/sync/apply-actions/dispatch-parent-action/ignoremanipulation.ts
index 81d6712..e592bca 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/ignoremanipulation.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/ignoremanipulation.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -81,6 +81,12 @@ export async function dispatchIgnoreManipulation ({ action, cache }: {
}
}
+ if (action.ignoreManipulationFlags !== 0) {
+ deviceEntry.manipulationFlags = deviceEntry.manipulationFlags & (~action.ignoreManipulationFlags)
+ }
+
await deviceEntry.save({ transaction: cache.transaction })
cache.invalidiateDeviceList = true
+ cache.incrementTriggeredSyncLevel(1)
+ cache.incrementTargetedTriggeredSyncLevel(action.deviceId, 2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/incrementcategoryextratime.ts b/src/function/sync/apply-actions/dispatch-parent-action/incrementcategoryextratime.ts
index 17ae903..359260e 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/incrementcategoryextratime.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/incrementcategoryextratime.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -41,7 +41,7 @@ export async function dispatchIncrementCategoryExtraTime ({ action, cache }: {
await category.save({ transaction: cache.transaction })
cache.categoriesWithModifiedBaseData.add(category.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
const categoryEntry = await cache.database.category.findOne({
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/index.ts b/src/function/sync/apply-actions/dispatch-parent-action/index.ts
index 593a36b..a22d39a 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/index.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -18,6 +18,7 @@
import {
AddCategoryAppsAction,
AddCategoryNetworkIdAction,
+ AddParentU2fKeyAction,
AddUserAction,
ChangeParentPasswordAction,
CreateCategoryAction,
@@ -29,10 +30,11 @@ import {
IncrementCategoryExtraTimeAction,
ParentAction,
RemoveCategoryAppsAction,
+ RemoveParentU2fKeyAction,
RemoveUserAction,
+ ReportU2fLoginAction,
RenameChildAction,
ResetCategoryNetworkIdsAction,
- ResetParentBlockedTimesAction,
ReviewChildTaskAction,
SetCategoryExtraTimeAction,
SetCategoryForUnassignedAppsAction,
@@ -51,6 +53,7 @@ import {
UpdateCategoryBlockAllNotificationsAction,
UpdateCategoryBlockedTimesAction,
UpdateCategoryDisableLimitsAction,
+ UpdateCategoryFlagsAction,
UpdateCategorySortingAction,
UpdateCategoryTemporarilyBlockedAction,
UpdateCategoryTimeWarningsAction,
@@ -59,17 +62,19 @@ import {
UpdateDeviceNameAction,
UpdateEnableActivityLevelBlockingAction,
UpdateNetworkTimeVerificationAction,
- UpdateParentBlockedTimesAction,
UpdateParentNotificationFlagsAction,
UpdateTimelimitRuleAction,
UpdateUserFlagsAction,
- UpdateUserLimitLoginCategory
+ UpdateUserLimitLoginCategory,
+ UpdateUserLimitLoginPreBlockDuration
} from '../../../../action'
import { Cache } from '../cache'
import { ActionObjectTypeNotHandledException } from '../exception/illegal-state'
import { ActionNotSupportedBySelfLimitationException } from '../exception/self-limit'
+import { AuthenticationMethod } from '../types'
import { dispatchAddCategoryApps } from './addcategoryapps'
import { dispatchAddCategoryNetworkId } from './addcategorynetworkid'
+import { dispatchAddU2f } from './addu2fkey'
import { dispatchAddUser } from './adduser'
import { dispatchChangeParentPassword } from './changeparentpassword'
import { dispatchCreateCategory } from './createcategory'
@@ -80,10 +85,11 @@ import { dispatchDeleteTimeLimitRule } from './deletetimelimitrule'
import { dispatchIgnoreManipulation } from './ignoremanipulation'
import { dispatchIncrementCategoryExtraTime } from './incrementcategoryextratime'
import { dispatchRemoveCategoryApps } from './removecategoryapps'
+import { dispatchRemoveU2f } from './removeu2fkey'
import { dispatchRemoveUser } from './removeuser'
+import { dispatchReportU2fLogin } from './reportu2flogin'
import { dispatchRenameChild } from './renamechild'
import { dispatchResetCategoryNetworkIds } from './resetcategorynetworkids'
-import { dispatchResetParentBlockedTimes } from './resetparentblockedtimes'
import { dispatchReviewChildTaskAction } from './reviewchildtaskaction'
import { dispatchSetCategoryExtraTime } from './setcategoryextratime'
import { dispatchSetCategoryForUnassignedApps } from './setcategoryforunassignedapps'
@@ -102,6 +108,7 @@ import { dispatchUpdateCategoryBatteryLimit } from './updatecategorybatterylimit
import { dispatchUpdateCategoryBlockAllNotifications } from './updatecategoryblockallnotifications'
import { dispatchUpdateCategoryBlockedTimes } from './updatecategoryblockedtimes'
import { dispatchUpdateCategoryDisableLimits } from './updatecategorydisablelimits'
+import { dispatchUpdateCategoryFlagsAction } from './updatecategoryflags'
import { dispatchUpdateCategorySorting } from './updatecategorysorting'
import { dispatchUpdateCategoryTemporarilyBlocked } from './updatecategorytemporarilyblocked'
import { dispatchUpdateCategoryTimeWarnings } from './updatecategorytimewarnings'
@@ -110,18 +117,22 @@ import { dispatchUpdateChildTaskAction } from './updatechildtaskaction'
import { dispatchUpdateDeviceName } from './updatedevicename'
import { dispatchUpdateEnableActivityLevelBlocking } from './updateenableactivitylevelblocking'
import { dispatchUpdateNetworkTimeVerification } from './updatenetworktimeverification'
-import { dispatchUpdateParentBlockedTimes } from './updateparentblockedtimes'
import { dispatchUpdateParentNotificationFlags } from './updateparentnotificationflags'
import { dispatchUpdateTimelimitRule } from './updatetimelimitrule'
import { dispatchUpdateUserFlagsAction } from './updateuserflags'
import { dispatchUpdateUserLimitLoginCategoryAction } from './updateuserlimitlogincategory'
+import { dispatchUpdateUserLimitPreBlockDuration } from './updateuserlimitloginpreblockduration'
-export const dispatchParentAction = async ({ action, cache, parentUserId, sourceDeviceId, fromChildSelfLimitAddChildUserId }: {
+export const dispatchParentAction = async ({
+ action, cache, parentUserId, sourceDeviceId,
+ fromChildSelfLimitAddChildUserId, authentication
+}: {
action: ParentAction
cache: Cache
parentUserId: string
sourceDeviceId: string | null
fromChildSelfLimitAddChildUserId: string | null
+ authentication: AuthenticationMethod
}) => {
if (action instanceof AddCategoryAppsAction) {
return dispatchAddCategoryApps({ action, cache, fromChildSelfLimitAddChildUserId })
@@ -139,6 +150,8 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source
return dispatchUpdateCategoryBlockedTimes({ action, cache, fromChildSelfLimitAddChildUserId })
} else if (action instanceof UpdateCategoryDisableLimitsAction) {
return dispatchUpdateCategoryDisableLimits({ action, cache, fromChildSelfLimitAddChildUserId })
+ } else if (action instanceof UpdateTimelimitRuleAction) {
+ return dispatchUpdateTimelimitRule({ action, cache, fromChildSelfLimitAddChildUserId })
}
if (fromChildSelfLimitAddChildUserId !== null) {
@@ -146,10 +159,14 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source
} else {
if (action instanceof AddCategoryNetworkIdAction) {
return dispatchAddCategoryNetworkId({ action, cache })
+ } else if (action instanceof AddParentU2fKeyAction) {
+ return dispatchAddU2f({ action, cache, parentUserId })
} else if (action instanceof AddUserAction) {
return dispatchAddUser({ action, cache })
} else if (action instanceof RemoveCategoryAppsAction) {
return dispatchRemoveCategoryApps({ action, cache })
+ } else if (action instanceof RemoveParentU2fKeyAction) {
+ return dispatchRemoveU2f({ action, cache, parentUserId, authentication })
} else if (action instanceof DeleteCategoryAction) {
return dispatchDeleteCategory({ action, cache })
} else if (action instanceof UpdateCategoryTitleAction) {
@@ -180,6 +197,8 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source
return dispatchSetUserTimezone({ action, cache })
} else if (action instanceof UpdateCategoryBatteryLimitAction) {
return dispatchUpdateCategoryBatteryLimit({ action, cache })
+ } else if (action instanceof UpdateCategoryFlagsAction) {
+ return dispatchUpdateCategoryFlagsAction({ action, cache })
} else if (action instanceof UpdateCategorySortingAction) {
return dispatchUpdateCategorySorting({ action, cache })
} else if (action instanceof IncrementCategoryExtraTimeAction) {
@@ -194,10 +213,10 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source
return dispatchUpdateNetworkTimeVerification({ action, cache })
} else if (action instanceof UpdateParentNotificationFlagsAction) {
return dispatchUpdateParentNotificationFlags({ action, cache })
- } else if (action instanceof UpdateTimelimitRuleAction) {
- return dispatchUpdateTimelimitRule({ action, cache })
} else if (action instanceof RemoveUserAction) {
return dispatchRemoveUser({ action, cache, parentUserId })
+ } else if (action instanceof ReportU2fLoginAction) {
+ return dispatchReportU2fLogin({ action, cache, authentication })
} else if (action instanceof ResetCategoryNetworkIdsAction) {
return dispatchResetCategoryNetworkIds({ action, cache })
} else if (action instanceof RenameChildAction) {
@@ -208,10 +227,6 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source
return dispatchIgnoreManipulation({ action, cache })
} else if (action instanceof UpdateCategoryTimeWarningsAction) {
return dispatchUpdateCategoryTimeWarnings({ action, cache })
- } else if (action instanceof ResetParentBlockedTimesAction) {
- return dispatchResetParentBlockedTimes({ action, cache })
- } else if (action instanceof UpdateParentBlockedTimesAction) {
- return dispatchUpdateParentBlockedTimes({ action, cache, parentUserId })
} else if (action instanceof UpdateUserFlagsAction) {
return dispatchUpdateUserFlagsAction({ action, cache })
} else if (action instanceof UpdateUserLimitLoginCategory) {
@@ -222,6 +237,8 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source
await dispatchReviewChildTaskAction({ action, cache })
} else if (action instanceof UpdateChildTaskAction) {
await dispatchUpdateChildTaskAction({ action, cache })
+ } else if (action instanceof UpdateUserLimitLoginPreBlockDuration) {
+ await dispatchUpdateUserLimitPreBlockDuration({ action, cache, parentUserId })
} else {
throw new ActionObjectTypeNotHandledException()
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/removecategoryapps.ts b/src/function/sync/apply-actions/dispatch-parent-action/removecategoryapps.ts
index d5f0f31..91d2d4f 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/removecategoryapps.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/removecategoryapps.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -42,5 +42,5 @@ export async function dispatchRemoveCategoryApps ({ action, cache }: {
}
cache.categoriesWithModifiedApps.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/removeu2fkey.ts b/src/function/sync/apply-actions/dispatch-parent-action/removeu2fkey.ts
new file mode 100644
index 0000000..964090d
--- /dev/null
+++ b/src/function/sync/apply-actions/dispatch-parent-action/removeu2fkey.ts
@@ -0,0 +1,47 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { RemoveParentU2fKeyAction } from '../../../../action'
+import { getU2fKeyId } from '../../../../database/u2fkey'
+import { Cache } from '../cache'
+import { ApplyActionUnacceptableAuthMethodException } from '../exception/auth'
+import { AuthenticationMethod } from '../types'
+
+export async function dispatchRemoveU2f ({ action, cache, parentUserId, authentication }: {
+ action: RemoveParentU2fKeyAction
+ cache: Cache
+ parentUserId: string
+ authentication: AuthenticationMethod
+}) {
+ if (authentication === 'u2f') {
+ throw new ApplyActionUnacceptableAuthMethodException()
+ }
+
+ await cache.database.u2fKey.destroy({
+ where: {
+ familyId: cache.familyId,
+ keyId: getU2fKeyId({ keyHandle: action.keyHandle, publicKey: action.publicKey }),
+ userId: parentUserId,
+ keyHandle: action.keyHandle,
+ publicKey: action.publicKey
+ },
+ transaction: cache.transaction
+ })
+
+ cache.invalidateU2fList = true
+ cache.incrementTriggeredSyncLevel(2)
+}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/removeuser.ts b/src/function/sync/apply-actions/dispatch-parent-action/removeuser.ts
index dc450ea..1e09eb5 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/removeuser.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/removeuser.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -106,8 +106,7 @@ export async function dispatchRemoveUser ({ action, cache, parentUserId }: {
familyId: cache.familyId,
childId: action.userId
},
- transaction: cache.transaction,
- lock: Sequelize.Transaction.LOCK.UPDATE
+ transaction: cache.transaction
})
await cache.database.categoryApp.destroy({
@@ -179,7 +178,7 @@ export async function dispatchRemoveUser ({ action, cache, parentUserId }: {
await user.destroy({ transaction: cache.transaction })
cache.invalidiateUserList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
cache.doesUserExist.cache.set(action.userId, false)
cache.getSecondPasswordHashOfParent.cache.delete(action.userId)
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/renamechild.ts b/src/function/sync/apply-actions/dispatch-parent-action/renamechild.ts
index 51f9560..95689b7 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/renamechild.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/renamechild.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -49,4 +49,5 @@ export async function dispatchRenameChild ({ action, cache }: {
cache.invalidiateUserList = true
cache.doesUserExist.cache.set(action.childId, false)
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/reportu2flogin.ts b/src/function/sync/apply-actions/dispatch-parent-action/reportu2flogin.ts
new file mode 100644
index 0000000..8a87710
--- /dev/null
+++ b/src/function/sync/apply-actions/dispatch-parent-action/reportu2flogin.ts
@@ -0,0 +1,34 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { ReportU2fLoginAction } from '../../../../action'
+import { Cache } from '../cache'
+import { ApplyActionUnacceptableAuthMethodException } from '../exception/auth'
+import { AuthenticationMethod } from '../types'
+
+export async function dispatchReportU2fLogin ({ authentication }: {
+ action: ReportU2fLoginAction
+ cache: Cache
+ authentication: AuthenticationMethod
+}) {
+ if (authentication !== 'u2f') {
+ throw new ApplyActionUnacceptableAuthMethodException()
+ }
+
+ // nothing to do; the goal was already reached by the authentication
+ // validation that expired the dh key
+}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/resetcategorynetworkids.ts b/src/function/sync/apply-actions/dispatch-parent-action/resetcategorynetworkids.ts
index d71d730..aeaf013 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/resetcategorynetworkids.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/resetcategorynetworkids.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -45,5 +45,5 @@ export async function dispatchResetCategoryNetworkIds ({ action, cache }: {
})
cache.categoriesWithModifiedBaseData.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/resetparentblockedtimes.ts b/src/function/sync/apply-actions/dispatch-parent-action/resetparentblockedtimes.ts
deleted file mode 100644
index e1e2bda..0000000
--- a/src/function/sync/apply-actions/dispatch-parent-action/resetparentblockedtimes.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import { ResetParentBlockedTimesAction } from '../../../../action'
-import { Cache } from '../cache'
-import { MissingUserException } from '../exception/missing-item'
-
-export async function dispatchResetParentBlockedTimes ({ action, cache }: {
- action: ResetParentBlockedTimesAction
- cache: Cache
-}) {
- const oldItem = await cache.database.user.findOne({
- where: {
- familyId: cache.familyId,
- userId: action.parentId,
- type: 'parent'
- },
- transaction: cache.transaction
- })
-
- if (!oldItem) {
- throw new MissingUserException()
- }
-
- await cache.database.user.update({
- blockedTimes: ''
- }, {
- where: {
- familyId: cache.familyId,
- userId: action.parentId,
- type: 'parent'
- },
- transaction: cache.transaction
- })
-
- cache.invalidiateUserList = true
- cache.areChangesImportant = true
-}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/reviewchildtaskaction.ts b/src/function/sync/apply-actions/dispatch-parent-action/reviewchildtaskaction.ts
index c338bf2..0b6adf3 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/reviewchildtaskaction.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/reviewchildtaskaction.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -60,10 +60,13 @@ export async function dispatchReviewChildTaskAction ({ action, cache }: {
extraTimeDay: categoryInfoUnsafe.extraTimeDay
}
- if (categoryInfo.extraTimeDay !== 0 && categoryInfo.extraTimeInMillis > 0) {
- // if the current time is daily, then extend the daily time only
+ const resetDayBoundExtraTime = categoryInfo.extraTimeDay !== -1 &&
+ action.day !== undefined && categoryInfo.extraTimeDay !== action.day
+
+ if (resetDayBoundExtraTime) {
await cache.database.category.update({
- extraTimeInMillis: categoryInfo.extraTimeInMillis + taskInfo.extraTimeDuration
+ extraTimeInMillis: taskInfo.extraTimeDuration,
+ extraTimeDay: -1
}, {
where: {
familyId: cache.familyId,
@@ -73,8 +76,7 @@ export async function dispatchReviewChildTaskAction ({ action, cache }: {
})
} else {
await cache.database.category.update({
- extraTimeInMillis: categoryInfo.extraTimeInMillis + taskInfo.extraTimeDuration,
- extraTimeDay: -1
+ extraTimeInMillis: categoryInfo.extraTimeInMillis + taskInfo.extraTimeDuration
}, {
where: {
familyId: cache.familyId,
@@ -96,6 +98,8 @@ export async function dispatchReviewChildTaskAction ({ action, cache }: {
},
transaction: cache.transaction
})
+
+ cache.incrementTriggeredSyncLevel(2)
} else {
await cache.database.childTask.update({
pendingRequest: 0
@@ -109,4 +113,5 @@ export async function dispatchReviewChildTaskAction ({ action, cache }: {
}
cache.categoriesWithModifiedTasks.add(taskInfo.categoryId)
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setcategoryextratime.ts b/src/function/sync/apply-actions/dispatch-parent-action/setcategoryextratime.ts
index 06c1b39..6905588 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setcategoryextratime.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setcategoryextratime.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -52,5 +52,5 @@ export async function dispatchSetCategoryExtraTime ({ action, cache }: {
})
cache.categoriesWithModifiedBaseData.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setcategoryforunassignedapps.ts b/src/function/sync/apply-actions/dispatch-parent-action/setcategoryforunassignedapps.ts
index d21d9a1..21afdbf 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setcategoryforunassignedapps.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setcategoryforunassignedapps.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -78,5 +78,5 @@ export async function dispatchSetCategoryForUnassignedApps ({ action, cache }: {
})
cache.invalidiateUserList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setchildpassword.ts b/src/function/sync/apply-actions/dispatch-parent-action/setchildpassword.ts
index 6e7e634..de63d88 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setchildpassword.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setchildpassword.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,10 +15,10 @@
* along with this program. If not, see .
*/
-import * as Sequelize from 'sequelize'
import { SetChildPasswordAction } from '../../../../action'
import { Cache } from '../cache'
import { MissingUserException } from '../exception/missing-item'
+import { decryptParentPassword } from '../../../dh'
export async function dispatchSetChildPassword ({ action, cache }: {
action: SetChildPasswordAction
@@ -30,17 +30,18 @@ export async function dispatchSetChildPassword ({ action, cache }: {
userId: action.childUserId,
type: 'child'
},
- transaction: cache.transaction,
- lock: Sequelize.Transaction.LOCK.UPDATE
+ transaction: cache.transaction
})
if (!childEntry) {
throw new MissingUserException()
}
- childEntry.passwordHash = action.newPassword.hash
- childEntry.secondPasswordSalt = action.newPassword.secondSalt
- childEntry.secondPasswordHash = action.newPassword.secondHash
+ const newPassword = await decryptParentPassword({ cache, password: action.newPassword })
+
+ childEntry.passwordHash = newPassword.hash
+ childEntry.secondPasswordSalt = newPassword.secondSalt
+ childEntry.secondPasswordHash = newPassword.secondHash
await childEntry.save({ transaction: cache.transaction })
@@ -50,5 +51,5 @@ export async function dispatchSetChildPassword ({ action, cache }: {
}
cache.invalidiateUserList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setconsiderrebootmanipulation.ts b/src/function/sync/apply-actions/dispatch-parent-action/setconsiderrebootmanipulation.ts
index 398d0d1..19b4ae7 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setconsiderrebootmanipulation.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setconsiderrebootmanipulation.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -46,5 +46,7 @@ export async function dispatchSetConsiderRebootManipulation ({ action, cache }:
})
cache.invalidiateDeviceList = true
- cache.areChangesImportant = true
+
+ cache.incrementTriggeredSyncLevel(1)
+ cache.incrementTargetedTriggeredSyncLevel(action.deviceId, 2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setdevicedefaultuser.ts b/src/function/sync/apply-actions/dispatch-parent-action/setdevicedefaultuser.ts
index dea14b8..e1478bb 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setdevicedefaultuser.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setdevicedefaultuser.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -54,5 +54,7 @@ export async function dispatchSetDeviceDefaultUser ({ action, cache }: {
})
cache.invalidiateDeviceList = true
- cache.areChangesImportant = true
+
+ cache.incrementTriggeredSyncLevel(1)
+ cache.incrementTargetedTriggeredSyncLevel(action.deviceId, 2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setdevicedefaultusertimeout.ts b/src/function/sync/apply-actions/dispatch-parent-action/setdevicedefaultusertimeout.ts
index 645a56d..d7c43f3 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setdevicedefaultusertimeout.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setdevicedefaultusertimeout.ts
@@ -46,5 +46,7 @@ export async function dispatchSetDeviceDefaultUserTimeout ({ action, cache }: {
})
cache.invalidiateDeviceList = true
- cache.areChangesImportant = true
+
+ cache.incrementTriggeredSyncLevel(1)
+ cache.incrementTargetedTriggeredSyncLevel(action.deviceId, 2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setdeviceuser.ts b/src/function/sync/apply-actions/dispatch-parent-action/setdeviceuser.ts
index 3edf454..e365efd 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setdeviceuser.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setdeviceuser.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -55,5 +55,7 @@ export async function dispatchSetDeviceUser ({ action, cache }: {
})
cache.invalidiateDeviceList = true
- cache.areChangesImportant = true
+
+ cache.incrementTriggeredSyncLevel(1)
+ cache.incrementTargetedTriggeredSyncLevel(action.deviceId, 2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setkeepsignedin.ts b/src/function/sync/apply-actions/dispatch-parent-action/setkeepsignedin.ts
index 4a91c6d..319b01a 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setkeepsignedin.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setkeepsignedin.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -63,6 +63,8 @@ export async function dispatchSetKeepSignedIn ({ action, cache, parentUserId }:
if (affectedRows !== 0) {
cache.invalidiateDeviceList = true
- cache.areChangesImportant = true
+
+ cache.incrementTriggeredSyncLevel(1)
+ cache.incrementTargetedTriggeredSyncLevel(action.deviceId, 2)
}
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setparentcategory.ts b/src/function/sync/apply-actions/dispatch-parent-action/setparentcategory.ts
index b6cbc11..1f5e345 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setparentcategory.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setparentcategory.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -118,5 +118,5 @@ export async function dispatchSetParentCategory ({ action, cache, fromChildSelfL
})
cache.categoriesWithModifiedBaseData.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setrelaxprimarydevice.ts b/src/function/sync/apply-actions/dispatch-parent-action/setrelaxprimarydevice.ts
index a10a7c4..34b462e 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setrelaxprimarydevice.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setrelaxprimarydevice.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -48,5 +48,5 @@ export async function dispatchSetRelaxPrimaryDevice ({ action, cache }: {
})
cache.invalidiateUserList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setsenddeviceconnected.ts b/src/function/sync/apply-actions/dispatch-parent-action/setsenddeviceconnected.ts
index 04a4cac..9bb7aa7 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setsenddeviceconnected.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setsenddeviceconnected.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -42,4 +42,6 @@ export async function dispatchSetSendDeviceConnected ({ action, cache, sourceDev
cache.devicesWithModifiedShowDeviceConnected.set(action.deviceId, action.enable)
cache.invalidiateDeviceList = true
+
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setuserdisablelmitsuntil.ts b/src/function/sync/apply-actions/dispatch-parent-action/setuserdisablelmitsuntil.ts
index db51649..ede6514 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setuserdisablelmitsuntil.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setuserdisablelmitsuntil.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -55,5 +55,5 @@ export async function dispatchUserSetDisableLimitsUntil ({ action, cache }: {
})
cache.invalidiateUserList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/setusertimezone.ts b/src/function/sync/apply-actions/dispatch-parent-action/setusertimezone.ts
index c74da7c..c68787f 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/setusertimezone.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/setusertimezone.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -46,5 +46,5 @@ export async function dispatchSetUserTimezone ({ action, cache }: {
})
cache.invalidiateUserList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorybatterylimit.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorybatterylimit.ts
index b1329b6..24abf1c 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorybatterylimit.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorybatterylimit.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -46,5 +46,5 @@ export async function dispatchUpdateCategoryBatteryLimit ({ action, cache }: {
await categoryEntry.save({ transaction: cache.transaction })
cache.categoriesWithModifiedBaseData.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatecategoryblockallnotifications.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatecategoryblockallnotifications.ts
index 59c025c..4554a62 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatecategoryblockallnotifications.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatecategoryblockallnotifications.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -31,13 +31,18 @@ export async function dispatchUpdateCategoryBlockAllNotifications ({ action, cac
categoryId: action.categoryId
},
transaction: cache.transaction,
- attributes: ['childId']
+ attributes: ['childId', 'blockAllNotifications']
})
if (!categoryEntryUnsafe) {
throw new MissingCategoryException()
}
+ const categoryEntry = {
+ childId: categoryEntryUnsafe.childId,
+ blockAllNotifications: categoryEntryUnsafe.blockAllNotifications
+ }
+
if (fromChildSelfLimitAddChildUserId !== null) {
if (fromChildSelfLimitAddChildUserId !== categoryEntryUnsafe.childId) {
throw new CanNotModifyOtherUsersBySelfLimitationException()
@@ -46,10 +51,17 @@ export async function dispatchUpdateCategoryBlockAllNotifications ({ action, cac
if (!action.blocked) {
throw new SelfLimitationException({ staticMessage: 'can not disable notification filter as child' })
}
+
+ if (categoryEntry.blockAllNotifications && action.blockDelay !== undefined) {
+ throw new SelfLimitationException({ staticMessage: 'can not update the block delay as child' })
+ }
}
- const [affectedRows] = await cache.database.category.update({
+ const [affectedRows] = await cache.database.category.update(action.blockDelay === undefined ? {
blockAllNotifications: action.blocked
+ } : {
+ blockAllNotifications: action.blocked,
+ blockNotificationDelay: action.blockDelay.toString(10)
}, {
where: {
familyId: cache.familyId,
@@ -60,6 +72,6 @@ export async function dispatchUpdateCategoryBlockAllNotifications ({ action, cac
if (affectedRows !== 0) {
cache.categoriesWithModifiedBaseData.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatecategoryblockedtimes.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatecategoryblockedtimes.ts
index 10f7f39..c51a7a4 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatecategoryblockedtimes.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatecategoryblockedtimes.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -70,5 +70,5 @@ export async function dispatchUpdateCategoryBlockedTimes ({ action, cache, fromC
})
cache.categoriesWithModifiedBaseData.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorydisablelimits.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorydisablelimits.ts
index 65c857a..b7f917a 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorydisablelimits.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorydisablelimits.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -60,7 +60,7 @@ export async function dispatchUpdateCategoryDisableLimits ({ action, cache, from
}
const [affectedRows] = await cache.database.category.update({
- disableLimitsUntil: action.endTime
+ disableLimitsUntil: action.endTime.toString(10)
}, {
where: {
familyId: cache.familyId,
@@ -71,6 +71,6 @@ export async function dispatchUpdateCategoryDisableLimits ({ action, cache, from
if (affectedRows !== 0) {
cache.categoriesWithModifiedBaseData.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatecategoryflags.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatecategoryflags.ts
new file mode 100644
index 0000000..fb2a456
--- /dev/null
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatecategoryflags.ts
@@ -0,0 +1,53 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { UpdateCategoryFlagsAction } from '../../../../action'
+import { Cache } from '../cache'
+import { IllegalStateException } from '../exception/illegal-state'
+import { MissingCategoryException } from '../exception/missing-item'
+
+export async function dispatchUpdateCategoryFlagsAction ({ action, cache }: {
+ action: UpdateCategoryFlagsAction
+ cache: Cache
+}) {
+ const categoryEntry = await cache.database.category.findOne({
+ where: {
+ familyId: cache.familyId,
+ categoryId: action.categoryId
+ },
+ transaction: cache.transaction
+ })
+
+ if (!categoryEntry) {
+ throw new MissingCategoryException()
+ }
+
+ const oldFlags = parseInt(categoryEntry.flags, 10)
+
+ if (!Number.isSafeInteger(oldFlags)) {
+ throw new IllegalStateException({ staticMessage: 'oldFlags is not a safe integer' })
+ }
+
+ const newFlags = (oldFlags & ~action.modifiedBits) | action.newValues
+
+ categoryEntry.flags = newFlags.toString(10)
+
+ await categoryEntry.save({ transaction: cache.transaction })
+
+ cache.categoriesWithModifiedBaseData.add(action.categoryId)
+ cache.incrementTriggeredSyncLevel(2)
+}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorysorting.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorysorting.ts
index ec4d279..2b5369c 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorysorting.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorysorting.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -42,4 +42,6 @@ export async function dispatchUpdateCategorySorting ({ action, cache }: {
cache.categoriesWithModifiedBaseData.add(categoryId)
}
+
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytemporarilyblocked.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytemporarilyblocked.ts
index 0a66438..9672cfb 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytemporarilyblocked.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytemporarilyblocked.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -48,7 +48,7 @@ export async function dispatchUpdateCategoryTemporarilyBlocked ({ action, cache,
const categoryEntry = {
childId: categoryEntryUnsafe.childId,
temporarilyBlocked: categoryEntryUnsafe.temporarilyBlocked,
- temporarilyBlockedEndTime: categoryEntryUnsafe.temporarilyBlockedEndTime
+ temporarilyBlockedEndTime: parseInt(categoryEntryUnsafe.temporarilyBlockedEndTime, 10)
}
if (fromChildSelfLimitAddChildUserId !== null) {
@@ -69,7 +69,7 @@ export async function dispatchUpdateCategoryTemporarilyBlocked ({ action, cache,
const [affectedRows] = await cache.database.category.update({
temporarilyBlocked: action.blocked,
- temporarilyBlockedEndTime: action.blocked ? (action.endTime ?? 0) : 0
+ temporarilyBlockedEndTime: action.blocked ? (action.endTime ?? 0).toString(10) : '0'
}, {
where: {
familyId: cache.familyId,
@@ -80,6 +80,6 @@ export async function dispatchUpdateCategoryTemporarilyBlocked ({ action, cache,
if (affectedRows !== 0) {
cache.categoriesWithModifiedBaseData.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytimewarnings.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytimewarnings.ts
index 7748899..1c936e7 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytimewarnings.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytimewarnings.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -43,6 +43,28 @@ export async function dispatchUpdateCategoryTimeWarnings ({ action, cache }: {
await categoryEntry.save({ transaction: cache.transaction })
+ if (action.minutes !== undefined) {
+ if (action.enable) {
+ await cache.database.categoryTimeWarning.create({
+ familyId: cache.familyId,
+ categoryId: action.categoryId,
+ minutes: action.minutes
+ }, {
+ transaction: cache.transaction,
+ ignoreDuplicates: true
+ })
+ } else {
+ await cache.database.categoryTimeWarning.destroy({
+ where: {
+ familyId: cache.familyId,
+ categoryId: action.categoryId,
+ minutes: action.minutes
+ },
+ transaction: cache.transaction
+ })
+ }
+ }
+
cache.categoriesWithModifiedBaseData.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytitle.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytitle.ts
index d575031..d1e42d0 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytitle.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatecategorytitle.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -47,6 +47,6 @@ export async function dispatchUpdateCategoryTitle ({ action, cache }: {
if (affectedRows !== 0) {
cache.categoriesWithModifiedBaseData.add(action.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatechildtaskaction.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatechildtaskaction.ts
index 2b2a3d5..f416140 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatechildtaskaction.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatechildtaskaction.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -84,5 +84,6 @@ export async function dispatchUpdateChildTaskAction ({ action, cache }: {
cache.categoriesWithModifiedTasks.add(taskInfo.categoryId)
cache.categoriesWithModifiedTasks.add(action.categoryId)
+ cache.incrementTriggeredSyncLevel(1)
}
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatedevicename.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatedevicename.ts
index c052861..bd607f1 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatedevicename.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatedevicename.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -47,6 +47,6 @@ export async function dispatchUpdateDeviceName ({ action, cache }: {
if (affectedRows !== 0) {
cache.invalidiateDeviceList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(1)
}
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updateenableactivitylevelblocking.ts b/src/function/sync/apply-actions/dispatch-parent-action/updateenableactivitylevelblocking.ts
index 4050c1b..7f451cc 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updateenableactivitylevelblocking.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updateenableactivitylevelblocking.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -46,5 +46,6 @@ export async function dispatchUpdateEnableActivityLevelBlocking ({ action, cache
})
cache.invalidiateDeviceList = true
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(1)
+ cache.incrementTargetedTriggeredSyncLevel(action.deviceId, 2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatenetworktimeverification.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatenetworktimeverification.ts
index eb8475a..73f558c 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatenetworktimeverification.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatenetworktimeverification.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -46,5 +46,7 @@ export async function dispatchUpdateNetworkTimeVerification ({ action, cache }:
})
cache.invalidiateDeviceList = true
- cache.areChangesImportant = true
+
+ cache.incrementTriggeredSyncLevel(1)
+ cache.incrementTargetedTriggeredSyncLevel(action.deviceId, 1)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updateparentblockedtimes.ts b/src/function/sync/apply-actions/dispatch-parent-action/updateparentblockedtimes.ts
deleted file mode 100644
index 12a46e4..0000000
--- a/src/function/sync/apply-actions/dispatch-parent-action/updateparentblockedtimes.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import { UpdateParentBlockedTimesAction } from '../../../../action'
-import { Cache } from '../cache'
-import { ApplyActionException } from '../exception/index'
-import { MissingUserException } from '../exception/missing-item'
-
-export async function dispatchUpdateParentBlockedTimes ({ action, cache, parentUserId }: {
- action: UpdateParentBlockedTimesAction
- cache: Cache
- parentUserId: string
-}) {
- if (parentUserId !== action.parentId && action.blockedTimes !== '') {
- throw new ApplyActionException({ staticMessage: 'only a parent itself can add limits' })
- }
-
- const oldUser = await cache.database.user.findOne({
- where: {
- familyId: cache.familyId,
- userId: action.parentId,
- type: 'parent'
- },
- transaction: cache.transaction
- })
-
- if (!oldUser) {
- throw new MissingUserException()
- }
-
- await cache.database.user.update({
- blockedTimes: action.blockedTimes
- }, {
- where: {
- familyId: cache.familyId,
- userId: action.parentId,
- type: 'parent'
- },
- transaction: cache.transaction
- })
-
- cache.invalidiateUserList = true
- cache.areChangesImportant = true
-}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updateparentnotificationflags.ts b/src/function/sync/apply-actions/dispatch-parent-action/updateparentnotificationflags.ts
index 2465de7..90ff047 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updateparentnotificationflags.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updateparentnotificationflags.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -45,4 +45,5 @@ export async function dispatchUpdateParentNotificationFlags ({ action, cache }:
await parentEntry.save({ transaction: cache.transaction })
cache.invalidiateUserList = true
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updatetimelimitrule.ts b/src/function/sync/apply-actions/dispatch-parent-action/updatetimelimitrule.ts
index 176958c..a39a026 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updatetimelimitrule.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updatetimelimitrule.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -17,11 +17,17 @@
import { UpdateTimelimitRuleAction } from '../../../../action'
import { Cache } from '../cache'
-import { MissingRuleException } from '../exception/missing-item'
+import { MissingRuleException, MissingCategoryException } from '../exception/missing-item'
+import {
+ CanNotModifyOtherUsersBySelfLimitationException, CanNotRelaxRestrictionsSelfLimitException
+} from '../exception/self-limit'
-export async function dispatchUpdateTimelimitRule ({ action, cache }: {
+export async function dispatchUpdateTimelimitRule ({
+ action, cache, fromChildSelfLimitAddChildUserId
+}: {
action: UpdateTimelimitRuleAction
cache: Cache
+ fromChildSelfLimitAddChildUserId: string | null
}) {
const ruleEntry = await cache.database.timelimitRule.findOne({
where: {
@@ -35,6 +41,53 @@ export async function dispatchUpdateTimelimitRule ({ action, cache }: {
throw new MissingRuleException()
}
+ if (fromChildSelfLimitAddChildUserId != null) {
+ const categoryEntryUnsafe = await cache.database.category.findOne({
+ where: {
+ familyId: cache.familyId,
+ categoryId: ruleEntry.categoryId
+ },
+ transaction: cache.transaction,
+ attributes: ['childId']
+ })
+
+ if (!categoryEntryUnsafe) {
+ throw new MissingCategoryException()
+ }
+
+ const categoryEntry = {
+ childId: categoryEntryUnsafe.childId
+ }
+
+
+ if (fromChildSelfLimitAddChildUserId !== categoryEntry.childId) {
+ throw new CanNotModifyOtherUsersBySelfLimitationException()
+ }
+
+ const wasSessionDurationLimitationEnabled =
+ ruleEntry.sessionPauseMilliseconds > 0 && ruleEntry.sessionDurationMilliseconds > 0
+
+ const countOldAffectedDays = Array(7)
+ .fill(0)
+ .reduce((sum, _, index) => sum + ((ruleEntry.dayMaskAsBitmask >> index) & 1), 0)
+
+ const isAtLeastAsStrictAsPreviously =
+ action.maximumTimeInMillis <= ruleEntry.maximumTimeInMillis &&
+ (action.dayMask & ruleEntry.dayMaskAsBitmask) === ruleEntry.dayMaskAsBitmask &&
+ (action.applyToExtraTimeUsage || !ruleEntry.applyToExtraTimeUsage) &&
+ action.start <= ruleEntry.startMinuteOfDay &&
+ action.end >= ruleEntry.endMinuteOfDay &&
+ (!wasSessionDurationLimitationEnabled || (
+ action.sessionDurationMilliseconds <= ruleEntry.sessionDurationMilliseconds &&
+ action.sessionPauseMilliseconds >= ruleEntry.sessionPauseMilliseconds
+ )) &&
+ (!action.perDay || ruleEntry.perDay || countOldAffectedDays <= 1)
+
+ if (!isAtLeastAsStrictAsPreviously) {
+ throw new CanNotRelaxRestrictionsSelfLimitException()
+ }
+ }
+
ruleEntry.applyToExtraTimeUsage = action.applyToExtraTimeUsage
ruleEntry.dayMaskAsBitmask = action.dayMask
ruleEntry.maximumTimeInMillis = action.maximumTimeInMillis
@@ -42,9 +95,10 @@ export async function dispatchUpdateTimelimitRule ({ action, cache }: {
ruleEntry.endMinuteOfDay = action.end
ruleEntry.sessionDurationMilliseconds = action.sessionDurationMilliseconds
ruleEntry.sessionPauseMilliseconds = action.sessionPauseMilliseconds
+ ruleEntry.perDay = action.perDay ? 1 : 0
await ruleEntry.save({ transaction: cache.transaction })
cache.categoriesWithModifiedTimeLimitRules.add(ruleEntry.categoryId)
- cache.areChangesImportant = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updateuserflags.ts b/src/function/sync/apply-actions/dispatch-parent-action/updateuserflags.ts
index 4e40900..c8127ec 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updateuserflags.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updateuserflags.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -49,4 +49,5 @@ export async function dispatchUpdateUserFlagsAction ({ action, cache }: {
await userEntry.save({ transaction: cache.transaction })
cache.invalidiateUserList = true
+ cache.incrementTriggeredSyncLevel(1)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updateuserlimitlogincategory.ts b/src/function/sync/apply-actions/dispatch-parent-action/updateuserlimitlogincategory.ts
index 6b7e419..be1d88c 100644
--- a/src/function/sync/apply-actions/dispatch-parent-action/updateuserlimitlogincategory.ts
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updateuserlimitlogincategory.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -68,11 +68,13 @@ export async function dispatchUpdateUserLimitLoginCategoryAction ({ action, cach
await cache.database.userLimitLoginCategory.create({
familyId: cache.familyId,
userId: action.userId,
- categoryId: action.categoryId
+ categoryId: action.categoryId,
+ preBlockDuration: 0
}, {
transaction: cache.transaction
})
}
cache.invalidiateUserList = true
+ cache.incrementTriggeredSyncLevel(2)
}
diff --git a/src/function/sync/apply-actions/dispatch-parent-action/updateuserlimitloginpreblockduration.ts b/src/function/sync/apply-actions/dispatch-parent-action/updateuserlimitloginpreblockduration.ts
new file mode 100644
index 0000000..4eed512
--- /dev/null
+++ b/src/function/sync/apply-actions/dispatch-parent-action/updateuserlimitloginpreblockduration.ts
@@ -0,0 +1,73 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { UpdateUserLimitLoginPreBlockDuration } from '../../../../action'
+import { Cache } from '../cache'
+import { ApplyActionException } from '../exception/index'
+import { MissingItemException, MissingUserException } from '../exception/missing-item'
+
+export async function dispatchUpdateUserLimitPreBlockDuration ({ action, cache, parentUserId }: {
+ action: UpdateUserLimitLoginPreBlockDuration
+ cache: Cache
+ parentUserId: string
+}) {
+ const userEntry = await cache.database.user.findOne({
+ where: {
+ familyId: cache.familyId,
+ userId: action.userId,
+ type: 'parent'
+ },
+ transaction: cache.transaction
+ })
+
+ if (!userEntry) {
+ throw new MissingUserException()
+ }
+
+ if (action.preBlockDuration !== 0 && parentUserId !== action.userId) {
+ throw new ApplyActionException({
+ staticMessage: 'only the parent user itself can add a limit login pre block duration'
+ })
+ }
+
+ const preBlockItem = await cache.database.userLimitLoginCategory.findOne({
+ transaction: cache.transaction,
+ where: {
+ familyId: cache.familyId,
+ userId: action.userId
+ }
+ })
+
+ if (preBlockItem === null) {
+ throw new MissingItemException({
+ staticMessage: 'you can not set a pre block duration if there is no pre block item'
+ })
+ }
+
+ await cache.database.userLimitLoginCategory.update({
+ preBlockDuration: action.preBlockDuration
+ }, {
+ transaction: cache.transaction,
+ where: {
+ familyId: cache.familyId,
+ userId: action.userId
+ }
+ })
+
+ cache.invalidiateUserList = true
+ cache.incrementTriggeredSyncLevel(2)
+}
diff --git a/src/function/sync/apply-actions/exception/auth.ts b/src/function/sync/apply-actions/exception/auth.ts
new file mode 100644
index 0000000..8507426
--- /dev/null
+++ b/src/function/sync/apply-actions/exception/auth.ts
@@ -0,0 +1,22 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { ApplyActionException } from './index'
+
+export class ApplyActionUnacceptableAuthMethodException extends ApplyActionException {
+ constructor() { super({ staticMessage: 'invalid auth method for the action' }) }
+}
diff --git a/src/function/sync/apply-actions/exception/integrity.ts b/src/function/sync/apply-actions/exception/integrity.ts
index 3f733eb..0a1a493 100644
--- a/src/function/sync/apply-actions/exception/integrity.ts
+++ b/src/function/sync/apply-actions/exception/integrity.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -27,6 +27,10 @@ export class InvalidParentActionIntegrityValue extends ApplyActionIntegrityExcep
constructor () { super({ staticMessage: 'invalid parent action integrity value' }) }
}
+export class InvalidU2fIntegrityValue extends ApplyActionIntegrityException {
+ constructor (message: string) { super({ staticMessage: 'invalid parent action u2f integrity value: ' + message }) }
+}
+
export class InvalidChildActionIntegrityValue extends ApplyActionIntegrityException {
constructor () { super({ staticMessage: 'invalid child action integrity value' }) }
}
diff --git a/src/function/sync/apply-actions/exception/limit.ts b/src/function/sync/apply-actions/exception/limit.ts
new file mode 100644
index 0000000..6ec8122
--- /dev/null
+++ b/src/function/sync/apply-actions/exception/limit.ts
@@ -0,0 +1,24 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { ApplyActionException } from './index'
+
+export class LimitReachedException extends ApplyActionException {
+ constructor({type}: { type: string }) {
+ super({ staticMessage: 'limit reached: ' + type })
+ }
+}
diff --git a/src/function/sync/apply-actions/exception/self-limit.ts b/src/function/sync/apply-actions/exception/self-limit.ts
index f3b9241..809c527 100644
--- a/src/function/sync/apply-actions/exception/self-limit.ts
+++ b/src/function/sync/apply-actions/exception/self-limit.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -32,3 +32,9 @@ export class ActionNotSupportedBySelfLimitationException extends SelfLimitationE
}
export class SelfLimitNotPossibleException extends SelfLimitationException {}
+
+export class CanNotRelaxRestrictionsSelfLimitException extends SelfLimitationException {
+ constructor () {
+ super({ staticMessage: 'can not relax restrictions with the self limitation' })
+ }
+}
diff --git a/src/function/sync/apply-actions/index.ts b/src/function/sync/apply-actions/index.ts
index c83c902..67949a9 100644
--- a/src/function/sync/apply-actions/index.ts
+++ b/src/function/sync/apply-actions/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -18,7 +18,7 @@
import { BadRequest } from 'http-errors'
import { ClientPushChangesRequest } from '../../../api/schema'
import { VisibleConnectedDevicesManager } from '../../../connected-devices'
-import { Database } from '../../../database'
+import { Database, shouldRetryWithException } from '../../../database'
import { EventHandler } from '../../../monitoring/eventhandler'
import { WebsocketApi } from '../../../websocket'
import { notifyClientsAboutChangesDelayed } from '../../websocket'
@@ -54,6 +54,7 @@ export const applyActionsFromDevice = async ({ database, request, websocket, con
hasFullVersion: baseInfo.hasFullVersion,
transaction,
familyId: baseInfo.familyId,
+ deviceId: baseInfo.deviceId,
connectedDevicesManager
})
@@ -70,12 +71,6 @@ export const applyActionsFromDevice = async ({ database, request, websocket, con
// update the next sequence number
nextSequenceNumber = action.sequenceNumber + 1
- const { isChildLimitAdding } = await assertActionIntegrity({
- deviceId: baseInfo.deviceId,
- cache,
- action
- })
-
if (action.type === 'appLogic') {
await dispatchAppLogicAction({
action,
@@ -84,14 +79,27 @@ export const applyActionsFromDevice = async ({ database, request, websocket, con
eventHandler
})
} else if (action.type === 'parent') {
+ const { isChildLimitAdding, authentication } = await assertActionIntegrity({
+ deviceId: baseInfo.deviceId,
+ cache,
+ action
+ })
+
await dispatchParentAction({
action,
cache,
deviceId: baseInfo.deviceId,
eventHandler,
- isChildLimitAdding
+ isChildLimitAdding,
+ authentication
})
} else if (action.type === 'child') {
+ await assertActionIntegrity({
+ deviceId: baseInfo.deviceId,
+ cache,
+ action
+ })
+
await dispatchChildAction({
action,
cache,
@@ -104,7 +112,11 @@ export const applyActionsFromDevice = async ({ database, request, websocket, con
}
})
} catch (ex) {
- if (ex instanceof ApplyActionException) {
+ if (shouldRetryWithException(database, ex)) {
+ eventHandler.countEvent('applyActionsFromDevice got exception which should cause retry')
+
+ throw ex
+ } else if (ex instanceof ApplyActionException) {
eventHandler.countEvent('applyActionsFromDevice errorDispatchingAction:' + ex.staticMessage)
} else {
const stack = ex instanceof Error && ex.stack ? ex.stack.substring(0, 4096) : 'no stack'
@@ -112,7 +124,7 @@ export const applyActionsFromDevice = async ({ database, request, websocket, con
eventHandler.countEvent('applyActionsFromDevice errorDispatchingAction:other:' + stack)
}
- cache.requireFullSync()
+ cache.requireSenderFullSync()
}
}
@@ -136,20 +148,25 @@ export const applyActionsFromDevice = async ({ database, request, websocket, con
await notifyClientsAboutChangesDelayed({
familyId: baseInfo.familyId,
sourceDeviceId: baseInfo.deviceId,
- isImportant: cache.areChangesImportant,
websocket,
database,
- transaction
+ transaction,
+ generalLevel: cache.triggeredSyncLevel,
+ targetedLevels: cache.targetedTriggeredSyncLevels
})
- if (cache.areChangesImportant) {
+ if (cache.triggeredSyncLevel === 2) {
transaction.afterCommit(() => {
eventHandler.countEvent('applyActionsFromDevice areChangesImportant')
})
+ } else if ([...cache.targetedTriggeredSyncLevels.entries()].some((entry) => entry[1] === 2)) {
+ transaction.afterCommit(() => {
+ eventHandler.countEvent('applyActionsFromDevice areChangesImportantTargeted')
+ })
}
return {
- shouldDoFullSync: cache.shouldDoFullSync()
+ shouldDoFullSync: cache.isSenderDoFullSyncTrue()
}
})
}
diff --git a/src/function/sync/apply-actions/integrity.ts b/src/function/sync/apply-actions/integrity.ts
index 8e5bf6d..087f075 100644
--- a/src/function/sync/apply-actions/integrity.ts
+++ b/src/function/sync/apply-actions/integrity.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,20 +15,26 @@
* along with this program. If not, see .
*/
-import { createHash } from 'crypto'
+import { createHash, createHmac, timingSafeEqual } from 'crypto'
import { ClientPushChangesRequestAction } from '../../../api/schema'
+import { intToBuffer, longToBuffer } from '../../../util/binary-number'
+import { validateU2fIntegrity, U2fValidationError } from '../../u2f'
import { Cache } from './cache'
import {
- InvalidChildActionIntegrityValue, InvalidParentActionIntegrityValue, ParentDeviceActionWithoutParentDeviceException
+ InvalidChildActionIntegrityValue, InvalidParentActionIntegrityValue,
+ ParentDeviceActionWithoutParentDeviceException, InvalidU2fIntegrityValue
} from './exception/integrity'
+import { ActionObjectTypeNotHandledException } from './exception/illegal-state'
+import { AuthenticationMethod } from './types'
export async function assertActionIntegrity ({ action, cache, deviceId }: {
action: ClientPushChangesRequestAction
cache: Cache
deviceId: string
-}): Promise<{ isChildLimitAdding: boolean }> {
- let isChildLimitAdding = false
-
+}): Promise<{
+ isChildLimitAdding: boolean
+ authentication: AuthenticationMethod
+}> {
if (action.type === 'parent') {
if (action.integrity === 'device') {
const deviceEntryUnsafe = await cache.database.device.findOne({
@@ -48,10 +54,69 @@ export async function assertActionIntegrity ({ action, cache, deviceId }: {
// this ensures that the parent exists
await cache.getSecondPasswordHashOfParent(action.userId)
+
+ return {
+ isChildLimitAdding: false,
+ authentication: 'device'
+ }
} else if (action.integrity === 'childDevice') {
- // will be checked later
- isChildLimitAdding = true
+ return {
+ isChildLimitAdding: true, // will be checked later
+ authentication: 'device'
+ }
+ } else if (action.integrity.startsWith('u2f:')) {
+ // this ensures that the parent exists
+ await cache.getSecondPasswordHashOfParent(action.userId)
+
+ try {
+ const checkResult = await validateU2fIntegrity({
+ integrity: action.integrity,
+ hasFullVersion: cache.hasFullVersion,
+ familyId: cache.familyId,
+ deviceId,
+ database: cache.database,
+ transaction: cache.transaction,
+ calculateHmac: (secret) => calculateActionHmac({
+ action,
+ deviceId,
+ secret
+ })
+ })
+
+ if (checkResult.userId !== action.userId) {
+ throw new InvalidParentActionIntegrityValue()
+ }
+ } catch (ex) {
+ if (ex instanceof U2fValidationError) throw new InvalidU2fIntegrityValue(ex.message)
+ else throw ex
+ }
+
+ return {
+ isChildLimitAdding: false,
+ authentication: 'u2f'
+ }
+ } else if (action.integrity.startsWith('password:')) {
+ // password method with hmac
+ const parentSecondHash = await cache.getSecondPasswordHashOfParent(action.userId)
+
+ const correctResponse = calculateActionHmac({
+ action,
+ deviceId,
+ secret: Buffer.from(parentSecondHash, 'utf8')
+ })
+
+ const providedResult = Buffer.from(action.integrity.substring(9), 'base64')
+
+ if (!timingSafeEqual(providedResult, correctResponse)) {
+ throw new InvalidParentActionIntegrityValue()
+ }
+
+ return {
+ isChildLimitAdding: false,
+ authentication: 'password'
+ }
} else {
+ // legacy password method
const parentSecondHash = await cache.getSecondPasswordHashOfParent(action.userId)
const integrityData = action.sequenceNumber.toString(10) +
@@ -64,10 +129,13 @@ export async function assertActionIntegrity ({ action, cache, deviceId }: {
if (action.integrity !== expectedIntegrityValue) {
throw new InvalidParentActionIntegrityValue()
}
- }
- }
- if (action.type === 'child') {
+ return {
+ isChildLimitAdding: false,
+ authentication: 'password'
+ }
+ }
+ } else if (action.type === 'child') {
const childSecondHash = await cache.getSecondPasswordHashOfChild(action.userId)
const integrityData = action.sequenceNumber.toString(10) +
@@ -80,7 +148,29 @@ export async function assertActionIntegrity ({ action, cache, deviceId }: {
if (action.integrity !== expectedIntegrityValue) {
throw new InvalidChildActionIntegrityValue()
}
- }
- return { isChildLimitAdding }
+ return {
+ isChildLimitAdding: false,
+ authentication: 'password'
+ }
+ } else {
+ throw new ActionObjectTypeNotHandledException()
+ }
+}
+
+function calculateActionHmac({ action, deviceId, secret }: {
+ action: ClientPushChangesRequestAction
+ deviceId: string
+ secret: Buffer
+}): Buffer {
+ const binaryDeviceId = Buffer.from(deviceId, 'utf8')
+ const binaryAction = Buffer.from(action.encodedAction, 'utf8')
+
+ return createHmac('sha256', secret)
+ .update(longToBuffer(BigInt(action.sequenceNumber)))
+ .update(intToBuffer(binaryDeviceId.length))
+ .update(binaryDeviceId)
+ .update(intToBuffer(binaryAction.length))
+ .update(binaryAction)
+ .digest()
}
diff --git a/src/function/sync/apply-actions/types.ts b/src/function/sync/apply-actions/types.ts
new file mode 100644
index 0000000..37dcd83
--- /dev/null
+++ b/src/function/sync/apply-actions/types.ts
@@ -0,0 +1,18 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+export type AuthenticationMethod = 'device' | 'password' | 'u2f'
diff --git a/src/function/sync/get-server-data-status/app-list.ts b/src/function/sync/get-server-data-status/app-list.ts
deleted file mode 100644
index 797f666..0000000
--- a/src/function/sync/get-server-data-status/app-list.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import { difference, filter } from 'lodash'
-import * as Sequelize from 'sequelize'
-import { Database } from '../../../database'
-import { ClientDataStatusApps } from '../../../object/clientdatastatus'
-import { ServerInstalledAppsData } from '../../../object/serverdatastatus'
-import { GetServerDataStatusIllegalStateException } from './exception'
-import { FamilyEntry } from './family-entry'
-
-export async function getAppList ({ database, transaction, familyEntry, appsStatus }: {
- database: Database
- transaction: Sequelize.Transaction
- familyEntry: FamilyEntry
- appsStatus: ClientDataStatusApps
-}): Promise | null> {
- const serverInstalledAppsVersions = (await database.device.findAll({
- where: {
- familyId: familyEntry.familyId
- },
- attributes: ['deviceId', 'installedAppsVersion'],
- transaction
- })).map((item) => ({
- deviceId: item.deviceId,
- installedAppsVersion: item.installedAppsVersion
- }))
-
- const getServerInstalledAppsVersionByDeviceId = (deviceId: string) => {
- const entry = serverInstalledAppsVersions.find((item) => item.deviceId === deviceId)
-
- if (!entry) {
- throw new GetServerDataStatusIllegalStateException({ staticMessage: 'could not find device entry' })
- }
-
- return entry.installedAppsVersion
- }
-
- const serverDeviceIds = serverInstalledAppsVersions.map((item) => item.deviceId)
- const clientDeviceIds = Object.keys(appsStatus)
- const addedDeviceIds = difference(serverDeviceIds, clientDeviceIds)
- const deviceIdsWhereInstalledAppsHaveChanged = filter(Object.keys(appsStatus), (deviceId) => {
- const installedAppsVersion = appsStatus[deviceId]
-
- const serverEntry = serverInstalledAppsVersions.find((item) => item.deviceId === deviceId)
-
- return !!serverEntry && serverEntry.installedAppsVersion !== installedAppsVersion
- })
- const idsOfDevicesWhereInstalledAppsMustBeSynced = [...addedDeviceIds, ...deviceIdsWhereInstalledAppsHaveChanged]
-
- if (idsOfDevicesWhereInstalledAppsMustBeSynced.length > 0) {
- const [appsToSync, activitiesToSync] = await Promise.all([
- database.app.findAll({
- where: {
- familyId: familyEntry.familyId,
- deviceId: {
- [Sequelize.Op.in]: idsOfDevicesWhereInstalledAppsMustBeSynced
- }
- },
- attributes: [
- 'deviceId',
- 'packageName',
- 'title',
- 'isLaunchable',
- 'recommendation'
- ],
- transaction
- }).map((item) => ({
- deviceId: item.deviceId,
- packageName: item.packageName,
- title: item.title,
- isLaunchable: item.isLaunchable,
- recommendation: item.recommendation
- })),
- database.appActivity.findAll({
- where: {
- familyId: familyEntry.familyId,
- deviceId: {
- [Sequelize.Op.in]: idsOfDevicesWhereInstalledAppsMustBeSynced
- }
- },
- attributes: [
- 'deviceId',
- 'packageName',
- 'title',
- 'activityName'
- ],
- transaction
- }).map((item) => ({
- deviceId: item.deviceId,
- packageName: item.packageName,
- activityName: item.activityName,
- title: item.title
- }))
- ])
-
- return idsOfDevicesWhereInstalledAppsMustBeSynced.map((deviceId): ServerInstalledAppsData => ({
- deviceId,
- apps: appsToSync.filter((item) => item.deviceId === deviceId).map((item) => ({
- packageName: item.packageName,
- title: item.title,
- isLaunchable: item.isLaunchable,
- recommendation: item.recommendation
- })),
- activities: activitiesToSync.filter((item) => item.deviceId === deviceId).map((item) => ({
- p: item.packageName,
- c: item.activityName,
- t: item.title
- })),
- version: getServerInstalledAppsVersionByDeviceId(deviceId)
- }))
- } else return null // no changes
-}
diff --git a/src/function/sync/get-server-data-status/category/base-data.ts b/src/function/sync/get-server-data-status/category/base-data.ts
index 22c7325..696c2c4 100644
--- a/src/function/sync/get-server-data-status/category/base-data.ts
+++ b/src/function/sync/get-server-data-status/category/base-data.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -51,7 +51,9 @@ export async function getCategoryBaseDatas ({
'minBatteryMobile',
'temporarilyBlockedEndTime',
'sort',
- 'disableLimitsUntil'
+ 'disableLimitsUntil',
+ 'flags',
+ 'blockNotificationDelay'
],
transaction
})).map((item) => ({
@@ -70,7 +72,9 @@ export async function getCategoryBaseDatas ({
minBatteryMobile: item.minBatteryMobile,
temporarilyBlockedEndTime: item.temporarilyBlockedEndTime,
sort: item.sort,
- disableLimitsUntil: item.disableLimitsUntil
+ disableLimitsUntil: item.disableLimitsUntil,
+ flags: item.flags,
+ blockNotificationDelay: item.blockNotificationDelay
}))
const networkIdsForSyncing = (await database.categoryNetworkId.findAll({
@@ -92,6 +96,23 @@ export async function getCategoryBaseDatas ({
hashedNetworkId: item.hashedNetworkId
}))
+ const additionalTimeWarningsForSyncing = (await database.categoryTimeWarning.findAll({
+ where: {
+ familyId: familyEntry.familyId,
+ categoryId: {
+ [Sequelize.Op.in]: categoryIdsToSyncBaseData
+ }
+ },
+ attributes: [
+ 'categoryId',
+ 'minutes'
+ ],
+ transaction
+ })).map((item) => ({
+ categoryId: item.categoryId,
+ minutes: item.minutes
+ }))
+
return dataForSyncing.map((item): ServerUpdatedCategoryBaseData => ({
categoryId: item.categoryId,
childId: item.childId,
@@ -106,7 +127,7 @@ export async function getCategoryBaseDatas ({
timeWarnings: item.timeWarningFlags,
mblMobile: item.minBatteryMobile,
mblCharging: item.minBatteryCharging,
- tempBlockTime: item.temporarilyBlockedEndTime,
+ tempBlockTime: parseInt(item.temporarilyBlockedEndTime, 10),
sort: item.sort,
networks: networkIdsForSyncing
.filter((network) => network.categoryId === item.categoryId)
@@ -114,6 +135,11 @@ export async function getCategoryBaseDatas ({
itemId: network.networkItemId,
hashedNetworkId: network.hashedNetworkId
})),
- dlu: parseInt(item.disableLimitsUntil, 10)
+ dlu: parseInt(item.disableLimitsUntil, 10),
+ flags: parseInt(item.flags, 10),
+ blockNotificationDelay: parseInt(item.blockNotificationDelay, 10),
+ atw: additionalTimeWarningsForSyncing
+ .filter((timeWarning) => timeWarning.categoryId === item.categoryId)
+ .map((timeWarning) => timeWarning.minutes)
}))
}
diff --git a/src/function/sync/get-server-data-status/category/rules.ts b/src/function/sync/get-server-data-status/category/rules.ts
index 393554a..263e01a 100644
--- a/src/function/sync/get-server-data-status/category/rules.ts
+++ b/src/function/sync/get-server-data-status/category/rules.ts
@@ -44,7 +44,8 @@ export async function getRules ({ database, transaction, categoryIdsToSyncRules,
'startMinuteOfDay',
'endMinuteOfDay',
'sessionDurationMilliseconds',
- 'sessionPauseMilliseconds'
+ 'sessionPauseMilliseconds',
+ 'perDay'
],
transaction
})).map((item) => ({
@@ -56,7 +57,8 @@ export async function getRules ({ database, transaction, categoryIdsToSyncRules,
startMinuteOfDay: item.startMinuteOfDay,
endMinuteOfDay: item.endMinuteOfDay,
sessionDurationMilliseconds: item.sessionDurationMilliseconds,
- sessionPauseMilliseconds: item.sessionPauseMilliseconds
+ sessionPauseMilliseconds: item.sessionPauseMilliseconds,
+ perDay: item.perDay
}))
const getCategoryRulesVersion = (categoryId: string) => (
@@ -73,7 +75,8 @@ export async function getRules ({ database, transaction, categoryIdsToSyncRules,
start: item.startMinuteOfDay,
end: item.endMinuteOfDay,
session: item.sessionDurationMilliseconds,
- pause: item.sessionPauseMilliseconds
+ pause: item.sessionPauseMilliseconds,
+ perDay: item.perDay !== 0 ? true : false
})),
version: getCategoryRulesVersion(categoryId)
}))
diff --git a/src/function/sync/get-server-data-status/device-detail.ts b/src/function/sync/get-server-data-status/device-detail.ts
new file mode 100644
index 0000000..8e9211d
--- /dev/null
+++ b/src/function/sync/get-server-data-status/device-detail.ts
@@ -0,0 +1,119 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { Database } from '../../../database'
+import { ClientDataStatusDevicesExtended } from '../../../object/clientdatastatus'
+import { ServerExtendedDeviceData, ServerCryptContainer } from '../../../object/serverdatastatus'
+import { FamilyEntry } from './family-entry'
+import { types } from '../../../database/encryptedapplist'
+
+export async function getDeviceDetailList ({ database, transaction, familyEntry, devicesDetail }: {
+ database: Database
+ transaction: Sequelize.Transaction
+ familyEntry: FamilyEntry
+ devicesDetail: ClientDataStatusDevicesExtended
+}): Promise | null> {
+ const serverEncryptedAppsVersions = (await database.encryptedAppList.findAll({
+ where: {
+ familyId: familyEntry.familyId,
+ },
+ attributes: ['deviceId', 'type', 'version'],
+ transaction
+ })).map((item) => ({
+ deviceId: item.deviceId,
+ type: item.type,
+ version: item.version
+ }))
+
+ const devicesWithChangedBaseApps: Array = []
+ const devicesWithChangedDiffApps: Array = []
+
+ serverEncryptedAppsVersions.forEach((item) => {
+ if (item.type === types.base) {
+ if (!devicesDetail[item.deviceId] || devicesDetail[item.deviceId].appsB !== item.version) {
+ devicesWithChangedBaseApps.push(item.deviceId)
+ }
+ } else if (item.type === types.diff) {
+ if (!devicesDetail[item.deviceId] || devicesDetail[item.deviceId].appsD !== item.version) {
+ devicesWithChangedDiffApps.push(item.deviceId)
+ }
+ }
+ })
+
+ const updatedDeviceIds = Array.from(new Set([...devicesWithChangedBaseApps, ...devicesWithChangedDiffApps]))
+
+ if (updatedDeviceIds.length === 0) return null
+
+ const updatedBaseApps = devicesWithChangedBaseApps.length === 0 ? [] : (await database.encryptedAppList.findAll({
+ where: {
+ familyId: familyEntry.familyId,
+ deviceId: {
+ [Sequelize.Op.in]: devicesWithChangedBaseApps
+ },
+ type: types.base
+ },
+ attributes: [
+ 'deviceId',
+ 'version',
+ 'data'
+ ],
+ transaction
+ })).map((item) => ({
+ deviceId: item.deviceId,
+ version: item.version,
+ data: item.data
+ }))
+
+ const updatedDiffApps = devicesWithChangedDiffApps.length === 0 ? [] : (await database.encryptedAppList.findAll({
+ where: {
+ familyId: familyEntry.familyId,
+ deviceId: {
+ [Sequelize.Op.in]: devicesWithChangedDiffApps
+ },
+ type: types.diff
+ },
+ attributes: [
+ 'deviceId',
+ 'version',
+ 'data'
+ ],
+ transaction
+ })).map((item) => ({
+ deviceId: item.deviceId,
+ version: item.version,
+ data: item.data
+ }))
+
+ return updatedDeviceIds.map((deviceId) => {
+ const appsBase = updatedBaseApps.find((item) => item.deviceId === deviceId)
+ const appsDiff = updatedDiffApps.find((item) => item.deviceId === deviceId)
+
+ return {
+ deviceId,
+ appsBase: appsBase ? wrapServerCryptContainer(appsBase) : undefined,
+ appsDiff: appsDiff ? wrapServerCryptContainer(appsDiff) : undefined
+ }
+ })
+}
+
+function wrapServerCryptContainer({ version, data }: { version: string, data: Buffer }): ServerCryptContainer {
+ return {
+ version,
+ data: data.toString('base64')
+ }
+}
diff --git a/src/function/sync/get-server-data-status/device-list.ts b/src/function/sync/get-server-data-status/device-list.ts
index 442d136..dbe2e16 100644
--- a/src/function/sync/get-server-data-status/device-list.ts
+++ b/src/function/sync/get-server-data-status/device-list.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -64,7 +64,11 @@ export async function getDeviceList ({ database, transaction, familyEntry }: {
asEnabled: item.asEnabled,
wasAsEnabled: item.wasAsEnabled,
activityLevelBlocking: item.activityLevelBlocking,
- qOrLater: item.isQorLater
+ qOrLater: item.isQorLater,
+ mFlags: item.manipulationFlags,
+ pk: item.publicKey ? item.publicKey.toString('base64') : undefined,
+ pType: item.platformType || undefined,
+ pLevel: item.platformLevel
}))
}
}
diff --git a/src/function/sync/get-server-data-status/dh-keys.ts b/src/function/sync/get-server-data-status/dh-keys.ts
new file mode 100644
index 0000000..7ff3f15
--- /dev/null
+++ b/src/function/sync/get-server-data-status/dh-keys.ts
@@ -0,0 +1,130 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { Database } from '../../../database'
+import { config, calculateExpireTime } from '../../../database/devicedhkey'
+import { ServerDhKey } from '../../../object/serverdatastatus'
+import { generateVersionId } from '../../../util/token'
+import { EventHandler } from '../../../monitoring/eventhandler'
+import { generateDhKeypair } from '../../../function/dh'
+import { FamilyEntry } from './family-entry'
+
+export async function getDeviceDhKeys ({
+ database, transaction, familyEntry, deviceId, lastVersionId, eventHandler
+}: {
+ database: Database
+ transaction: Sequelize.Transaction
+ familyEntry: FamilyEntry
+ deviceId: string
+ lastVersionId: string | null
+ eventHandler: EventHandler
+}): Promise {
+ const savedData = await database.deviceDhKey.findAll({
+ where: {
+ familyId: familyEntry.familyId,
+ deviceId
+ },
+ transaction
+ })
+
+ const now = BigInt(Date.now())
+ const oldCurrentKey = savedData.find((item) => item.expireAt === null)
+ const needsNewKey =
+ oldCurrentKey === undefined ||
+ BigInt(oldCurrentKey.createdAt) + BigInt(config.generateNewKeyAfterAge) <= now ||
+ BigInt(oldCurrentKey.createdAt) > now
+
+ if (needsNewKey) {
+ eventHandler.countEvent('getDeviceDhKeys:needsNewKey')
+
+ const newVersion = generateVersionId()
+ const newKeypair = await generateDhKeypair()
+
+ if (savedData.length >= 8) {
+ eventHandler.countEvent('getDeviceDhKeys:gc')
+
+ const elementToRemove = savedData.reduce((a, currentItem, currentIndex) => {
+ const b = { item: currentItem, index: currentIndex }
+
+ const createdA = BigInt(a.item.createdAt)
+ const createdB = BigInt(b.item.createdAt)
+
+ if (createdA > createdB) return b
+ else if (createdA < createdB) return a
+ else {
+ if (a.item.createdAtSubsequence > b.item.createdAtSubsequence) return b
+ else return a
+ }
+ }, { index: 0, item: savedData[0] })
+
+ await database.deviceDhKey.destroy({
+ where: {
+ familyId: familyEntry.familyId,
+ deviceId,
+ version: elementToRemove.item.version
+ },
+ transaction
+ })
+
+ savedData.splice(elementToRemove.index, 1)
+ }
+
+ await database.deviceDhKey.update({
+ expireAt: calculateExpireTime(now).toString(10)
+ }, {
+ where: {
+ familyId: familyEntry.familyId,
+ deviceId,
+ expireAt: null
+ },
+ transaction
+ })
+
+ const newItemCreatedAt = (now - now % BigInt(config.generationTimeRounding))
+
+ const newItemExistingSubsequenceValues =
+ savedData
+ .filter((item) => BigInt(item.createdAt) === newItemCreatedAt)
+ .map((item) => item.createdAtSubsequence)
+
+ const newItemCreatedAtSubsequence =
+ newItemExistingSubsequenceValues.reduce((max, item) => Math.max(max, item + 1), 0)
+
+ await database.deviceDhKey.create({
+ familyId: familyEntry.familyId,
+ deviceId,
+ version: newVersion,
+ createdAt: newItemCreatedAt.toString(10),
+ createdAtSubsequence: Math.min(newItemCreatedAtSubsequence, 1 << 30),
+ expireAt: null,
+ publicKey: newKeypair.publicKey,
+ privateKey: newKeypair.privateKey
+ }, { transaction })
+
+ return {
+ k: newKeypair.publicKey.toString('base64'),
+ v: newVersion
+ }
+ } else {
+ if (lastVersionId === oldCurrentKey.version) return null
+ else return {
+ k: oldCurrentKey.publicKey.toString('base64'),
+ v: oldCurrentKey.version
+ }
+ }
+}
diff --git a/src/function/sync/get-server-data-status/family-entry.ts b/src/function/sync/get-server-data-status/family-entry.ts
index 021653b..ad0bdc8 100644
--- a/src/function/sync/get-server-data-status/family-entry.ts
+++ b/src/function/sync/get-server-data-status/family-entry.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -25,6 +25,7 @@ export interface FamilyEntry {
userListVersion: string
hasFullVersion: boolean
fullVersionUntil: string
+ u2fKeysVersion: string
}
export async function getFamilyEntry ({ database, familyId, transaction }: {
@@ -40,7 +41,8 @@ export async function getFamilyEntry ({ database, familyId, transaction }: {
'deviceListVersion',
'userListVersion',
'hasFullVersion',
- 'fullVersionUntil'
+ 'fullVersionUntil',
+ 'u2fKeysVersion'
],
transaction
})
@@ -54,6 +56,7 @@ export async function getFamilyEntry ({ database, familyId, transaction }: {
deviceListVersion: familyEntryUnsafe.deviceListVersion,
userListVersion: familyEntryUnsafe.userListVersion,
hasFullVersion: familyEntryUnsafe.hasFullVersion,
- fullVersionUntil: familyEntryUnsafe.fullVersionUntil
+ fullVersionUntil: familyEntryUnsafe.fullVersionUntil,
+ u2fKeysVersion: familyEntryUnsafe.u2fKeysVersion
}
}
diff --git a/src/function/sync/get-server-data-status/index.ts b/src/function/sync/get-server-data-status/index.ts
index 2e720a4..ec708ae 100644
--- a/src/function/sync/get-server-data-status/index.ts
+++ b/src/function/sync/get-server-data-status/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -21,29 +21,44 @@ import { Database } from '../../../database'
import { getStatusMessage } from '../../../function/statusmessage'
import { ClientDataStatus } from '../../../object/clientdatastatus'
import { ServerDataStatus } from '../../../object/serverdatastatus'
-import { getAppList } from './app-list'
+import { EventHandler } from '../../../monitoring/eventhandler'
import {
getCategoryAssignedApps, getCategoryBaseDatas, getCategoryDataToSync,
getRules, getTasks, getUsedTimes
} from './category'
+import { getDeviceDetailList } from './device-detail'
import { getDeviceList } from './device-list'
+import { getDeviceDhKeys } from './dh-keys'
import { getFamilyEntry } from './family-entry'
import { getUserList } from './user-list'
+import { getKeyRequests } from './key-requests'
+import { getKeyResponses } from './key-responses'
+import { getU2f } from './u2f'
-export const generateServerDataStatus = async ({ database, clientStatus, familyId, transaction }: {
+export const generateServerDataStatus = async ({
+ database, clientStatus, familyId, deviceId, transaction, eventHandler
+}: {
database: Database
clientStatus: ClientDataStatus
familyId: string
+ deviceId: string
transaction: Sequelize.Transaction
+ eventHandler: EventHandler
}): Promise => {
- const familyEntry = await getFamilyEntry({ database, familyId, transaction })
- const doesClientSupportTasks = clientStatus.clientLevel !== undefined && clientStatus.clientLevel >= 3
+ const clientLevel = clientStatus.clientLevel || 0
- let result: ServerDataStatus = {
+ const familyEntry = await getFamilyEntry({ database, familyId, transaction })
+ const doesClientSupportTasks = clientLevel >= 3
+ const doesClientSupportCryptoApps = clientLevel >= 4
+ const doesClientSupportDh = clientLevel >= 5
+ const doesClientSupportU2f = clientLevel >= 6
+
+ const result: ServerDataStatus = {
fullVersion: config.alwaysPro ? 1 : (
familyEntry.hasFullVersion ? parseInt(familyEntry.fullVersionUntil, 10) : 0
),
- message: await getStatusMessage({ database, transaction }) || undefined
+ message: await getStatusMessage({ database, transaction }) || undefined,
+ apiLevel: 7
}
if (familyEntry.deviceListVersion !== clientStatus.devices) {
@@ -54,8 +69,6 @@ export const generateServerDataStatus = async ({ database, clientStatus, familyI
result.users = await getUserList({ database, transaction, familyEntry })
}
- result.apps = await getAppList({ database, transaction, familyEntry, appsStatus: clientStatus.apps }) || undefined
-
const categoryDataToSync = await getCategoryDataToSync({ database, transaction, familyEntry, categoriesStatus: clientStatus.categories })
if (categoryDataToSync.removedCategoryIds.length > 0) {
@@ -102,5 +115,50 @@ export const generateServerDataStatus = async ({ database, clientStatus, familyI
})
}
+ if (doesClientSupportCryptoApps) {
+ result.devices2 = await getDeviceDetailList({
+ database,
+ transaction,
+ familyEntry,
+ devicesDetail: clientStatus.devicesDetail || {}
+ }) || undefined
+
+ result.krq = await getKeyRequests({
+ database,
+ transaction,
+ familyEntry,
+ deviceId,
+ lastSeenRequestIndex: clientStatus.kri || null
+ }) || undefined
+
+ result.kr = await getKeyResponses({
+ database,
+ transaction,
+ familyEntry,
+ deviceId,
+ lastSeenRequestIndex: clientStatus.kr || null
+ }) || undefined
+ }
+
+ if (doesClientSupportDh) {
+ result.dh = await getDeviceDhKeys({
+ database,
+ transaction,
+ familyEntry,
+ deviceId,
+ lastVersionId: clientStatus.dh || null,
+ eventHandler
+ }) || undefined
+ }
+
+ if (doesClientSupportU2f) {
+ result.u2f = await getU2f({
+ database,
+ transaction,
+ familyEntry,
+ lastVersionId: clientStatus.u2f || null
+ }) || undefined
+ }
+
return result
}
diff --git a/src/function/sync/get-server-data-status/key-requests.ts b/src/function/sync/get-server-data-status/key-requests.ts
new file mode 100644
index 0000000..a7184d3
--- /dev/null
+++ b/src/function/sync/get-server-data-status/key-requests.ts
@@ -0,0 +1,58 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { Database } from '../../../database'
+import { ServerKeyRequest } from '../../../object/serverdatastatus'
+import { FamilyEntry } from './family-entry'
+
+export async function getKeyRequests ({ database, transaction, familyEntry, lastSeenRequestIndex, deviceId }: {
+ database: Database
+ transaction: Sequelize.Transaction
+ familyEntry: FamilyEntry
+ lastSeenRequestIndex: number | null
+ deviceId: string
+}): Promise | null> {
+ const data = await database.keyRequest.findAll({
+ where: {
+ familyId: familyEntry.familyId,
+ senderDeviceId: {
+ [Sequelize.Op.ne]: deviceId
+ },
+ ...(lastSeenRequestIndex === null ? {} : {
+ serverSequenceNumber: {
+ [Sequelize.Op.gt]: lastSeenRequestIndex
+ }
+ })
+ },
+ transaction,
+ limit: 32
+ })
+
+ if (data.length === 0) return null
+
+ return data.map((item) => ({
+ srvSeq: parseInt(item.serverSequenceNumber),
+ senId: item.senderDeviceId,
+ senSeq: parseInt(item.senderSequenceNumber),
+ deviceId: item.deviceId || undefined,
+ categoryId: item.categoryId || undefined,
+ type: item.type,
+ tempKey: item.tempKey.toString('base64'),
+ signature: item.signature.toString('base64')
+ }))
+}
diff --git a/src/function/sync/get-server-data-status/key-responses.ts b/src/function/sync/get-server-data-status/key-responses.ts
new file mode 100644
index 0000000..b029454
--- /dev/null
+++ b/src/function/sync/get-server-data-status/key-responses.ts
@@ -0,0 +1,63 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { Database } from '../../../database'
+import { ServerKeyResponse } from '../../../object/serverdatastatus'
+import { FamilyEntry } from './family-entry'
+
+export async function getKeyResponses ({ database, transaction, familyEntry, lastSeenRequestIndex, deviceId }: {
+ database: Database
+ transaction: Sequelize.Transaction
+ familyEntry: FamilyEntry
+ lastSeenRequestIndex: number | null
+ deviceId: string
+}): Promise | null> {
+ if (lastSeenRequestIndex !== null) {
+ await database.keyResponse.destroy({
+ where: {
+ familyId: familyEntry.familyId,
+ receiverDeviceId: deviceId,
+ replyServerSequenceNumber: {
+ [Sequelize.Op.lte]: lastSeenRequestIndex.toString(10)
+ }
+ },
+ transaction
+ })
+ }
+
+ const data = await database.keyResponse.findAll({
+ where: {
+ familyId: familyEntry.familyId,
+ receiverDeviceId: deviceId,
+ },
+ order: [['replyServerSequenceNumber', 'ASC']],
+ transaction,
+ limit: 32
+ })
+
+ if (data.length === 0) return null
+
+ return data.map((item) => ({
+ srvSeq: parseInt(item.replyServerSequenceNumber),
+ sender: item.senderDeviceId,
+ rqSeq: parseInt(item.requestClientSequenceNumber),
+ tempKey: item.tempKey.toString('base64'),
+ cryptKey: item.encryptedKey.toString('base64'),
+ signature: item.signature.toString('base64')
+ }))
+}
diff --git a/src/function/sync/get-server-data-status/u2f.ts b/src/function/sync/get-server-data-status/u2f.ts
new file mode 100644
index 0000000..515aa94
--- /dev/null
+++ b/src/function/sync/get-server-data-status/u2f.ts
@@ -0,0 +1,49 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import * as Sequelize from 'sequelize'
+import { Database } from '../../../database'
+import { U2fData } from '../../../object/serverdatastatus'
+import { FamilyEntry } from './family-entry'
+
+export async function getU2f ({
+ database, transaction, familyEntry, lastVersionId
+}: {
+ database: Database
+ transaction: Sequelize.Transaction
+ familyEntry: FamilyEntry
+ lastVersionId: string | null
+}): Promise {
+ if (lastVersionId === familyEntry.u2fKeysVersion) return null
+
+ const savedData = await database.u2fKey.findAll({
+ where: {
+ familyId: familyEntry.familyId
+ },
+ transaction
+ })
+
+ return {
+ v: familyEntry.u2fKeysVersion,
+ d: savedData.map((item) => ({
+ u: item.userId,
+ a: parseInt(item.addedAt, 10),
+ h: item.keyHandle.toString('base64'),
+ p: item.publicKey.toString('base64')
+ }))
+ }
+}
diff --git a/src/function/sync/get-server-data-status/user-list.ts b/src/function/sync/get-server-data-status/user-list.ts
index f15426c..35063c1 100644
--- a/src/function/sync/get-server-data-status/user-list.ts
+++ b/src/function/sync/get-server-data-status/user-list.ts
@@ -42,7 +42,6 @@ export async function getUserList ({ database, transaction, familyEntry }: {
'categoryForNotAssignedApps',
'relaxPrimaryDeviceRule',
'mailNotificationFlags',
- 'blockedTimes',
'flags'
],
transaction
@@ -59,7 +58,6 @@ export async function getUserList ({ database, transaction, familyEntry }: {
categoryForNotAssignedApps: item.categoryForNotAssignedApps,
relaxPrimaryDeviceRule: item.relaxPrimaryDeviceRule,
mailNotificationFlags: item.mailNotificationFlags,
- blockedTimes: item.blockedTimes,
flags: item.flags
}))
@@ -69,19 +67,21 @@ export async function getUserList ({ database, transaction, familyEntry }: {
},
attributes: [
'userId',
- 'categoryId'
+ 'categoryId',
+ 'preBlockDuration'
],
transaction
})).map((item) => ({
userId: item.userId,
- categoryId: item.categoryId
+ categoryId: item.categoryId,
+ preBlockDuration: item.preBlockDuration
}))
const getLimitLoginCategory = (userId: string) => {
const item = limitLoginCategories.find((item) => item.userId === userId)
if (item) {
- return item.categoryId
+ return item
} else {
return undefined
}
@@ -89,22 +89,27 @@ export async function getUserList ({ database, transaction, familyEntry }: {
return {
version: familyEntry.userListVersion,
- data: users.map((item) => ({
- id: item.userId,
- name: item.name,
- password: item.passwordHash,
- secondPasswordSalt: item.secondPasswordSalt,
- type: item.type,
- timeZone: item.timeZone,
- disableLimitsUntil: parseInt(item.disableTimelimitsUntil, 10),
- mail: item.mail,
- currentDevice: item.currentDevice,
- categoryForNotAssignedApps: item.categoryForNotAssignedApps,
- relaxPrimaryDevice: item.relaxPrimaryDeviceRule,
- mailNotificationFlags: item.mailNotificationFlags,
- blockedTimes: item.blockedTimes,
- flags: parseInt(item.flags, 10),
- llc: getLimitLoginCategory(item.userId)
- }))
+ data: users.map((item) => {
+ const limitLoginCategory = getLimitLoginCategory(item.userId)
+
+ return {
+ id: item.userId,
+ name: item.name,
+ password: item.passwordHash,
+ secondPasswordSalt: item.secondPasswordSalt,
+ type: item.type,
+ timeZone: item.timeZone,
+ disableLimitsUntil: parseInt(item.disableTimelimitsUntil, 10),
+ mail: item.mail,
+ currentDevice: item.currentDevice,
+ categoryForNotAssignedApps: item.categoryForNotAssignedApps,
+ relaxPrimaryDevice: item.relaxPrimaryDeviceRule,
+ mailNotificationFlags: item.mailNotificationFlags,
+ blockedTimes: '',
+ flags: parseInt(item.flags, 10),
+ llc: limitLoginCategory?.categoryId,
+ pbd: limitLoginCategory?.preBlockDuration
+ }
+ })
}
}
diff --git a/src/function/u2f/index.ts b/src/function/u2f/index.ts
new file mode 100644
index 0000000..8052c4b
--- /dev/null
+++ b/src/function/u2f/index.ts
@@ -0,0 +1,148 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { createHash, timingSafeEqual } from 'crypto'
+import * as Sequelize from 'sequelize'
+import { getSharedSecret, SharedSecretException } from '../dh'
+import { Database } from '../../database'
+import { intToBuffer } from '../../util/binary-number'
+import { isU2fSignatureValid, calculateApplicationId } from '../../util/u2fsignature'
+
+export class U2fValidationError extends Error {}
+class IntegrityMalformedException extends U2fValidationError { constructor() { super('integrity malformed') } }
+class MissingPremiumException extends U2fValidationError { constructor() { super('missing premium') } }
+class U2fSharedSecretException extends U2fValidationError { constructor(message: string) { super('shared secret: ' + message) } }
+class HmacMismatchException extends U2fValidationError { constructor() { super('hmac mismatch') } }
+class UnknownU2fKeyIdException extends U2fValidationError { constructor() { super('unknown u2f key id') } }
+class InvalidU2fSignatureException extends U2fValidationError { constructor() { super('u2f signature invalid') } }
+
+export async function validateU2fIntegrity({
+ integrity,
+ hasFullVersion,
+ familyId,
+ deviceId,
+ database,
+ transaction,
+ calculateHmac
+}: {
+ integrity: string
+ hasFullVersion: boolean
+ familyId: string
+ deviceId: string
+ database: Database
+ transaction: Sequelize.Transaction
+ calculateHmac: (secret: Buffer) => Buffer
+}) {
+ if (!integrity.startsWith('u2f:')) throw new IntegrityMalformedException()
+
+ const parts = integrity.substring(4).split('.')
+
+ if (parts.length !== 5) {
+ throw new IntegrityMalformedException()
+ }
+
+ if (!hasFullVersion) {
+ throw new MissingPremiumException()
+ }
+
+ const [dhKeyId, dhPublicKeyBase64, u2fKeyId, u2fResponseBase64, providedHmacResultBase64] = parts
+
+ const binaryDhKeyId = Buffer.from(dhKeyId, 'utf8')
+ const dhPublicKey = Buffer.from(dhPublicKeyBase64, 'base64')
+ const u2fResponse = Buffer.from(u2fResponseBase64, 'base64')
+ const providedHmacResult = Buffer.from(providedHmacResultBase64, 'base64')
+
+ const sharedSecret = await (async () => {
+ try {
+ return await getSharedSecret({
+ database,
+ transaction,
+ familyId,
+ deviceId,
+ keyId: dhKeyId,
+ otherPublicKey: dhPublicKey
+ })
+ } catch (ex) {
+ if (ex instanceof SharedSecretException) throw new U2fSharedSecretException(ex.message)
+ else throw ex
+ }
+ })()
+
+ const correctHmac = calculateHmac(sharedSecret.sharedSecret)
+
+ if (!timingSafeEqual(providedHmacResult, correctHmac)) {
+ throw new HmacMismatchException()
+ }
+
+ const keyDescriptorUnsafe = await database.u2fKey.findOne({
+ where: {
+ familyId,
+ keyId: u2fKeyId
+ },
+ transaction,
+ attributes: ['publicKey', 'userId']
+ })
+
+ if (keyDescriptorUnsafe === null) throw new UnknownU2fKeyIdException()
+
+ const keyDescriptor = {
+ publicKey: keyDescriptorUnsafe.publicKey,
+ userId: keyDescriptorUnsafe.userId
+ }
+
+ const dhPublicKeysHash = createHash('sha256')
+ .update(intToBuffer(binaryDhKeyId.length))
+ .update(binaryDhKeyId)
+ .update(intToBuffer(sharedSecret.ownPublicKey.length))
+ .update(sharedSecret.ownPublicKey)
+ .update(intToBuffer(dhPublicKey.length))
+ .update(dhPublicKey)
+ .digest()
+
+ if (
+ !isU2fSignatureValid({
+ u2fRawResponse: u2fResponse,
+ applicationId: calculateApplicationId('https://timelimit.io'),
+ challenge: dhPublicKeysHash,
+ publicKey: keyDescriptor.publicKey
+ })
+ ) {
+ throw new InvalidU2fSignatureException()
+ }
+
+ const u2fCounter = u2fResponse.readUInt32BE(1)
+
+ // the counter is not checked at the server
+ // this happens because the offline usage can cause receiving actions
+ // out of order so it would be required to keep track of the used counter
+ // values; if this becomes necassary in the future, then it does not
+ // require any client modification to add it
+
+ await database.u2fKey.update({
+ nextCounter: (u2fCounter + 1).toString(10)
+ }, {
+ where: {
+ familyId,
+ keyId: u2fKeyId
+ },
+ transaction
+ })
+
+ return {
+ userId: keyDescriptor.userId
+ }
+}
diff --git a/src/function/warningmail/manipulation.ts b/src/function/warningmail/manipulation.ts
index 7735ea9..b43d3d2 100644
--- a/src/function/warningmail/manipulation.ts
+++ b/src/function/warningmail/manipulation.ts
@@ -15,7 +15,8 @@
* along with this program. If not, see .
*/
-import { Database, Transaction, warpPromiseReturner } from '../../database'
+import { Database, Transaction } from '../../database'
+import { mailNotificationFlags } from '../../database/user'
import { sendManipulationWarningMail } from '../../util/mail'
import { canSendWarningMail } from '../../util/ratelimit-warningmail'
@@ -35,10 +36,10 @@ export const sendManipulationWarnings = async ({ database, familyId, deviceName,
const targetMailAddresses = parentEntries
.filter((item) => item.mail !== '')
- .filter((item) => (item.mailNotificationFlags & 1) === 1)
+ .filter((item) => (item.mailNotificationFlags & mailNotificationFlags.warnings) === mailNotificationFlags.warnings)
.map((item) => item.mail)
- transaction.afterCommit(warpPromiseReturner(async () => {
+ transaction.afterCommit(async () => {
await Promise.all(
targetMailAddresses.map(async (receiver) => {
if (await canSendWarningMail(receiver)) {
@@ -46,5 +47,5 @@ export const sendManipulationWarnings = async ({ database, familyId, deviceName,
}
})
)
- }))
+ })
}
diff --git a/src/function/warningmail/taskdone.ts b/src/function/warningmail/taskdone.ts
new file mode 100644
index 0000000..d7d8b0d
--- /dev/null
+++ b/src/function/warningmail/taskdone.ts
@@ -0,0 +1,52 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2020 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { Database, Transaction } from '../../database'
+import { mailNotificationFlags } from '../../database/user'
+import { sendTaskDoneMail } from '../../util/mail'
+import { canSendTaskDoneMail } from '../../util/ratelimit-taskdonemail'
+
+export const sendTaskDoneMails = async ({ database, familyId, childName, taskTitle, transaction }: {
+ database: Database
+ familyId: string
+ childName: string
+ taskTitle: string
+ transaction: Transaction
+}) => {
+ const parentEntries = await database.user.findAll({
+ where: {
+ familyId,
+ type: 'parent'
+ },
+ transaction
+ })
+
+ const targetMailAddresses = parentEntries
+ .filter((item) => item.mail !== '')
+ .filter((item) => (item.mailNotificationFlags & mailNotificationFlags.tasks) === mailNotificationFlags.tasks)
+ .map((item) => item.mail)
+
+ transaction.afterCommit(async () => {
+ await Promise.all(
+ targetMailAddresses.map(async (receiver) => {
+ if (await canSendTaskDoneMail(receiver)) {
+ await sendTaskDoneMail({ receiver, child: childName, task: taskTitle })
+ }
+ })
+ )
+ })
+}
diff --git a/src/function/warningmail/uninstall.ts b/src/function/warningmail/uninstall.ts
index efd1545..49eae29 100644
--- a/src/function/warningmail/uninstall.ts
+++ b/src/function/warningmail/uninstall.ts
@@ -15,7 +15,8 @@
* along with this program. If not, see .
*/
-import { Database, Transaction, warpPromiseReturner } from '../../database'
+import { Database, Transaction } from '../../database'
+import { mailNotificationFlags } from '../../database/user'
import { sendUninstallWarningMail } from '../../util/mail'
import { canSendWarningMail } from '../../util/ratelimit-warningmail'
@@ -35,10 +36,10 @@ export const sendUninstallWarnings = async ({ database, familyId, deviceName, tr
const targetMailAddresses = parentEntries
.filter((item) => item.mail !== '')
- .filter((item) => (item.mailNotificationFlags & 1) === 1)
+ .filter((item) => (item.mailNotificationFlags & mailNotificationFlags.warnings) === mailNotificationFlags.warnings)
.map((item) => item.mail)
- transaction.afterCommit(warpPromiseReturner(async () => {
+ transaction.afterCommit(async () => {
await Promise.all(
targetMailAddresses.map(async (receiver) => {
if (await canSendWarningMail(receiver)) {
@@ -46,5 +47,5 @@ export const sendUninstallWarnings = async ({ database, familyId, deviceName, tr
}
})
)
- }))
+ })
}
diff --git a/src/function/websocket/index.ts b/src/function/websocket/index.ts
index de33f37..8564103 100644
--- a/src/function/websocket/index.ts
+++ b/src/function/websocket/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,39 +15,45 @@
* along with this program. If not, see .
*/
-import * as Sequelize from 'sequelize'
import { Database, Transaction } from '../../database'
import { WebsocketApi } from '../../websocket'
-export const notifyClientsAboutChangesDelayed = async ({ familyId, sourceDeviceId, database, websocket, isImportant, transaction }: {
+export const notifyClientsAboutChangesDelayed = async ({
+ familyId, sourceDeviceId, database,
+ websocket, transaction, generalLevel, targetedLevels
+}: {
familyId: string
sourceDeviceId: string | null // this device will not get an push
database: Database
websocket: WebsocketApi
- isImportant: boolean
transaction: Transaction
+ generalLevel: 0 | 1 | 2
+ targetedLevels: Map
}) => {
const relatedDeviceEntries = (await database.device.findAll({
- where: sourceDeviceId ? {
- familyId,
- deviceId: {
- [Sequelize.Op.not]: sourceDeviceId
- }
- } : {
+ where: {
familyId
},
- attributes: ['deviceAuthToken'],
+ attributes: ['deviceId', 'deviceAuthToken'],
transaction
})).map((item) => ({
+ deviceId: item.deviceId,
deviceAuthToken: item.deviceAuthToken
}))
transaction.afterCommit(() => {
- relatedDeviceEntries.forEach((item) => {
- websocket.triggerSyncByDeviceAuthToken({
- deviceAuthToken: item.deviceAuthToken,
- isImportant
- })
- })
+ for (const deviceEntry of relatedDeviceEntries) {
+ if (deviceEntry.deviceId === sourceDeviceId) continue
+
+ const targetedLevel = targetedLevels.get(deviceEntry.deviceId) ?? 0
+ const effectiveLevel = Math.max(targetedLevel, generalLevel)
+
+ if (effectiveLevel > 0) {
+ websocket.triggerSyncByDeviceAuthToken({
+ deviceAuthToken: deviceEntry.deviceAuthToken,
+ isImportant: effectiveLevel === 2
+ })
+ }
+ }
})
}
diff --git a/src/index.ts b/src/index.ts
index 260df4d..1ce7084 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -16,10 +16,11 @@
*/
import { Server } from 'http'
+import { pid } from 'process'
import { createApi } from './api'
import { config } from './config'
import { VisibleConnectedDevicesManager } from './connected-devices'
-import { assertNestedTransactionsAreWorking, defaultDatabase, defaultUmzug } from './database'
+import { assertNestedTransactionsAreWorking, assertSerializeableTransactionsAreWorking, defaultDatabase, defaultUmzug } from './database'
import { EventHandler } from './monitoring/eventhandler'
import { InMemoryEventHandler } from './monitoring/inmemoryeventhandler'
import { createWebsocketHandler } from './websocket'
@@ -31,6 +32,7 @@ async function main () {
const eventHandler: EventHandler = new InMemoryEventHandler()
await assertNestedTransactionsAreWorking(database)
+ await assertSerializeableTransactionsAreWorking(database)
const connectedDevicesManager = new VisibleConnectedDevicesManager({
database
@@ -60,7 +62,22 @@ async function main () {
pingInterval: config.pingInterval
})
- server.listen(process.env.PORT || 8080)
+ const port = process.env.PORT || 8080
+
+ if (port === 'socketactivation') {
+ if (process.env.LISTEN_FDS !== '1') {
+ console.warn('expecting exactly one file descriptor for the socket activation')
+ process.exit(1)
+ } else if (process.env.LISTEN_PID !== pid.toString(10)) {
+ console.warn('expecting handover of file descriptors to this process for the socket activation')
+ process.exit(1)
+ }
+
+ // the sockets are passed using fd 3 + index (with index = 0 in this case)
+ server.listen({ fd: 3 })
+ } else {
+ server.listen(port)
+ }
console.log('ready')
}
diff --git a/src/model/timelimitrule.ts b/src/model/timelimitrule.ts
index d82d627..f346dc5 100644
--- a/src/model/timelimitrule.ts
+++ b/src/model/timelimitrule.ts
@@ -28,10 +28,12 @@ export class TimelimitRule {
readonly end: number
readonly sessionDurationMilliseconds: number
readonly sessionPauseMilliseconds: number
+ readonly perDay: boolean
constructor ({
ruleId, categoryId, maxTimeInMillis, dayMask, applyToExtraTimeUsage,
- start, end, sessionDurationMilliseconds, sessionPauseMilliseconds
+ start, end, sessionDurationMilliseconds, sessionPauseMilliseconds,
+ perDay
}: {
ruleId: string
categoryId: string
@@ -42,6 +44,7 @@ export class TimelimitRule {
end: number
sessionDurationMilliseconds: number
sessionPauseMilliseconds: number
+ perDay: boolean
}) {
this.ruleId = ruleId
this.categoryId = categoryId
@@ -52,6 +55,7 @@ export class TimelimitRule {
this.end = end
this.sessionDurationMilliseconds = sessionDurationMilliseconds
this.sessionPauseMilliseconds = sessionPauseMilliseconds
+ this.perDay = perDay
assertIdWithinFamily(ruleId)
assertIdWithinFamily(categoryId)
@@ -98,7 +102,7 @@ export class TimelimitRule {
dur: this.sessionDurationMilliseconds
})
- static parse = ({ ruleId, categoryId, time, days, extraTime, start, end, dur, pause }: SerializedTimeLimitRule) => (
+ static parse = ({ ruleId, categoryId, time, days, extraTime, start, end, dur, pause, perDay }: SerializedTimeLimitRule) => (
new TimelimitRule({
ruleId,
categoryId,
@@ -108,7 +112,8 @@ export class TimelimitRule {
start: start ?? MinuteOfDay.MIN,
end: end ?? MinuteOfDay.MAX,
sessionDurationMilliseconds: dur ?? 0,
- sessionPauseMilliseconds: pause ?? 0
+ sessionPauseMilliseconds: pause ?? 0,
+ perDay: perDay ?? false
})
)
}
@@ -123,6 +128,7 @@ export interface SerializedTimeLimitRule {
end?: number
dur?: number
pause?: number
+ perDay?: boolean
}
export class ParseTimeLimitRuleException extends Error {}
diff --git a/src/object/clientdatastatus.ts b/src/object/clientdatastatus.ts
index 437db70..cece54a 100644
--- a/src/object/clientdatastatus.ts
+++ b/src/object/clientdatastatus.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -21,10 +21,28 @@ export interface ClientDataStatus {
categories: ClientDataStatusCategories
users: string // userListVersion
clientLevel?: number
+ devicesDetail?: ClientDataStatusDevicesExtended
+ kri?: number // last key request index
+ kr?: number // last key response index
+ dh?: string // last Diffie Hellman key version
+ u2f?: string // last u2f list version
+}
+
+export function createEmptyClientDataStatus({ clientLevel }: {
+ clientLevel: number | null
+}): ClientDataStatus {
+ return {
+ devices: '',
+ apps: {},
+ categories: {},
+ users: '',
+ clientLevel: clientLevel || undefined
+ }
}
export type ClientDataStatusApps = {[key: string]: string} // installedAppsVersionsByDeviceId
export type ClientDataStatusCategories = {[key: string]: CategoryDataStatus}
+export type ClientDataStatusDevicesExtended = {[key: string]: DeviceDataStatus}
export interface CategoryDataStatus {
base: string // baseVersion
@@ -33,3 +51,8 @@ export interface CategoryDataStatus {
usedTime: string // usedTimeItemsVersion
tasks?: string // taskListVersion
}
+
+export interface DeviceDataStatus {
+ appsB?: string // encrypted app list base version
+ appsD?: string // encrypted app list diff version
+}
diff --git a/src/object/serverdatastatus.ts b/src/object/serverdatastatus.ts
index 8ddefc5..effc808 100644
--- a/src/object/serverdatastatus.ts
+++ b/src/object/serverdatastatus.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -23,6 +23,7 @@ import { RuntimePermissionStatus } from '../model/runtimepermissionstatus'
export interface ServerDataStatus {
devices?: ServerDeviceList // newDeviceList
+ devices2?: Array // updatedExtendedDeviceData
apps?: Array // newInstalledApps
rmCategories?: Array // removedCategories
categoryBase?: Array // newCategoryBaseData
@@ -31,8 +32,13 @@ export interface ServerDataStatus {
rules?: Array // newOrUpdatedTimeLimitRules
tasks?: Array // newOrUpdatedTasks
users?: ServerUserList // newUserList
+ krq?: Array // pendingKeyRequests
+ kr?: Array // keyResponses
+ dh?: ServerDhKey // Diffie Hellman
+ u2f?: U2fData
fullVersion: number // fullVersionUntil
message?: string
+ apiLevel: number
}
export interface ServerDeviceList {
@@ -61,6 +67,7 @@ export interface ServerUserEntry {
blockedTimes: string
flags: number
llc?: string // limit login category
+ pbd?: number // pre block duration, default is zero
}
export interface ServerDeviceData {
@@ -94,6 +101,10 @@ export interface ServerDeviceData {
wasAsEnabled: boolean
activityLevelBlocking: boolean
qOrLater: boolean
+ mFlags: number // manipulation flags
+ pk?: string // public key
+ pType?: string
+ pLevel: number
}
export interface ServerUpdatedCategoryBaseData {
@@ -116,6 +127,10 @@ export interface ServerUpdatedCategoryBaseData {
networks: Array
// disable limits until
dlu: number
+ flags: number
+ blockNotificationDelay: number
+ // atw = additionalTimeWarnings
+ atw: Array
}
export interface ServerCategoryNetworkId {
@@ -187,6 +202,7 @@ export interface ServerTimeLimitRule {
end: number // endMinuteOfDay
session: number // maximum session duration
pause: number // session pause duration
+ perDay: boolean
}
export interface ServerUpdatedCategoryTasks {
@@ -209,3 +225,51 @@ export interface ServerInstalledAppsData {
apps: Array
activities: Array
}
+
+export interface ServerExtendedDeviceData {
+ deviceId: string
+ appsBase?: ServerCryptContainer
+ appsDiff?: ServerCryptContainer
+}
+
+export interface ServerCryptContainer {
+ version: string
+ data: string
+}
+
+export interface ServerKeyRequest {
+ srvSeq: number
+ senId: string
+ senSeq: number
+ deviceId?: string
+ categoryId?: string
+ type: number
+ tempKey: string
+ signature: string
+}
+
+export interface ServerKeyResponse {
+ srvSeq: number
+ sender: string
+ rqSeq: number
+ tempKey: string,
+ cryptKey: string,
+ signature: string
+}
+
+export interface ServerDhKey {
+ v: string // version
+ k: string // key, base64
+}
+
+export interface U2fData {
+ v: string // version
+ d: Array // data
+}
+
+export interface U2fItem {
+ u: string // userId
+ a: number // addedAt
+ h: string // key handle, base64
+ p: string // public key, base64
+}
diff --git a/src/util/binary-number.ts b/src/util/binary-number.ts
new file mode 100644
index 0000000..9c20324
--- /dev/null
+++ b/src/util/binary-number.ts
@@ -0,0 +1,32 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+export function intToBuffer(input: number): Buffer {
+ const buffer = Buffer.alloc(4)
+
+ buffer.writeUInt32BE(input)
+
+ return buffer
+}
+
+export function longToBuffer(input: bigint): Buffer {
+ const buffer = Buffer.alloc(8)
+
+ buffer.writeBigUInt64BE(input)
+
+ return buffer
+}
diff --git a/src/util/bitmask.ts b/src/util/bitmask.ts
index dcbe010..a0228de 100644
--- a/src/util/bitmask.ts
+++ b/src/util/bitmask.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -56,7 +56,7 @@ export const validateBitmask = (bitmask: string, maxLength: number) => {
export const validateAndParseBitmask = (bitmask: string, maxLength: number) => {
validateBitmask(bitmask, maxLength)
- const result = range(0, maxLength).map((_) => false)
+ const result = range(0, maxLength).map(() => false)
const splitpoints = split(bitmask, ',').map((item) => parseInt(item, 10))
diff --git a/src/util/identity-token.ts b/src/util/identity-token.ts
new file mode 100644
index 0000000..fb147a3
--- /dev/null
+++ b/src/util/identity-token.ts
@@ -0,0 +1,63 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { SignJWT, jwtVerify } from 'jose'
+import { config } from '../config'
+import { IdentityTokenPayload, IdentityTokenCreatePayload } from '../api/schema'
+import { isIdentityTokenPayload } from '../api/validator'
+
+export async function createIdentityToken({ purpose, familyId, userId, mail }: IdentityTokenCreatePayload) {
+ const jwt = await new SignJWT({ purpose, familyId, userId, mail })
+ .setExpirationTime('7d')
+ .setProtectedHeader({ alg: 'HS512' })
+ .sign(getSignSecret())
+
+ return Buffer.from(jwt, 'ascii')
+ .toString('base64')
+ .split(/(.{32})/)
+ .filter((item) => item.length > 0)
+ .join('\n')
+}
+
+export async function verifyIdentitifyToken(token: string): Promise {
+ try {
+ const { payload } = await jwtVerify(
+ Buffer.from(token, 'base64').toString('ascii'),
+ getSignSecret(),
+ { algorithms: ['HS512'] }
+ )
+
+ if (!isIdentityTokenPayload(payload)) throw new BadPayloadException()
+
+ return payload
+ } catch (ex) {
+ if (ex instanceof TokenValidationException) throw ex
+ else if (ex instanceof Error) throw new TokenValidationException(ex.message)
+ else throw ex
+ }
+}
+
+function getSignSecret(): Buffer {
+ if (config.signSecret === '') throw new MissingSignSecretException()
+
+ return Buffer.from(config.signSecret, 'utf8')
+}
+
+export class MissingSignSecretException extends Error {}
+
+export class TokenValidationException extends Error {}
+class BadPayloadException extends TokenValidationException { constructor() { super('bad payload') } }
diff --git a/src/util/mail.ts b/src/util/mail.ts
index e38404f..02e7e7a 100644
--- a/src/util/mail.ts
+++ b/src/util/mail.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2023 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,53 +15,109 @@
* along with this program. If not, see .
*/
+import { compile } from 'ejs'
import { parseOneAddress } from 'email-addresses'
-import * as Email from 'email-templates'
-import { join } from 'path'
+import { readFileSync } from 'fs'
+import { createTransport } from 'nodemailer'
+import { resolve } from 'path'
import { config } from '../config'
import { IllegalStateException } from '../exception'
const mailimprint = process.env.MAIL_IMPRINT || 'not defined'
const mailServerBlacklist = (process.env.MAIL_SERVER_BLACKLIST || '').split(',').filter((item) => !!item)
-const email = new Email({
- message: {
- from: process.env.MAIL_SENDER || ''
- },
- transport: JSON.parse(process.env.MAIL_TRANSPORT || 'null') || undefined,
- views: {
- options: {
- extension: 'ejs'
- }
- }
-})
+const mailSender = process.env.MAIL_SENDER || ''
+const mailTransportConfig = JSON.parse(process.env.MAIL_TRANSPORT || 'null') || undefined
+const isDevMode = process.env.NODE_ENV === 'development'
-export const sendAuthenticationMail = async ({ receiver, code, locale }: {receiver: string, code: string, locale: string}) => {
- await email.send({
- template: join(__dirname, '../../other/mail/login'),
- message: {
- to: receiver
- },
- locals: {
+const mailTransport = isDevMode || mailTransportConfig !== undefined ?
+ createTransport(isDevMode ? {
+ jsonTransport: true
+ } : mailTransportConfig) :
+ null
+
+function createMailTemplateSender (templateName: string) {
+ const compileTemplate = (filename: string) => compile(
+ readFileSync(resolve(__dirname, '../../other/mail', templateName, filename)).toString('utf8')
+ )
+
+ const subjectTemplate = compileTemplate('subject.ejs')
+ const textTemplate = compileTemplate('text.ejs')
+ const htmlTemplate = compileTemplate('html.ejs')
+
+ const sendMail = async ({ receiver, params }: {
+ receiver: string
+ params: object
+ }) => {
+ if (!mailTransport) {
+ throw new Error('can not send mails without mail config and without NODE_ENV=development')
+ }
+
+ const subject = subjectTemplate(params).replace(/\n/g, ' ')
+ const text = textTemplate(params)
+ const html = htmlTemplate(params)
+
+ await new Promise((resolve, reject) => {
+ mailTransport.sendMail({
+ from: mailSender,
+ to: receiver,
+ subject,
+ text,
+ html
+ }, (err, info) => {
+ if (err) {
+ reject(err)
+ } else {
+ if (isDevMode) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const data = (info as any).message
+
+ console.log(JSON.stringify({
+ ...JSON.parse(data),
+ params
+ }, null, 2))
+ }
+
+ resolve()
+ }
+ })
+ })
+ }
+
+ return { sendMail }
+}
+
+const loginMailSender = createMailTemplateSender('login')
+
+export const sendAuthenticationMail = async ({
+ receiver, code, locale, deviceName
+}: {
+ receiver: string, code: string, locale: string, deviceName: string | null
+}) => {
+ await loginMailSender.sendMail({
+ receiver,
+ params: {
subject: locale === 'de' ? 'Anmeldung bei TimeLimit' : 'Sign in at TimeLimit',
introtext: locale === 'de' ? 'Geben Sie zum Authentifizieren folgenden Code in TimeLimit ein' : 'To authenticate, enter the following code in TimeLimit',
code,
outrotext: locale === 'de' ? 'Geben Sie diesen Code nicht an Dritte weiter.' : 'Do not share this code with third parties.',
- mailimprint
+ mailimprint,
+ deviceName,
+ deviceNameIntro: locale === 'de' ? 'Die Anmeldung wurde am Gerät' : 'The login was attempted at the device',
+ deviceNameOutro: locale === 'de' ? 'versucht.' : '.'
}
})
}
+const manipulationMailSender = createMailTemplateSender('manipulation')
+
export const sendManipulationWarningMail = async ({ receiver, deviceName }: {
receiver: string
deviceName: string
}) => {
- await email.send({
- template: join(__dirname, '../../other/mail/manipulation'),
- message: {
- to: receiver
- },
- locals: {
+ await manipulationMailSender.sendMail({
+ receiver,
+ params: {
subject: 'TimeLimit@' + deviceName + ' - Manipulation',
deviceName,
mailimprint
@@ -69,16 +125,15 @@ export const sendManipulationWarningMail = async ({ receiver, deviceName }: {
})
}
+const uninstallMailSender = createMailTemplateSender('uninstall')
+
export const sendUninstallWarningMail = async ({ receiver, deviceName }: {
receiver: string
deviceName: string
}) => {
- await email.send({
- template: join(__dirname, '../../other/mail/uninstall'),
- message: {
- to: receiver
- },
- locals: {
+ await uninstallMailSender.sendMail({
+ receiver,
+ params: {
subject: 'TimeLimit removed from ' + deviceName,
deviceName,
mailimprint
@@ -86,6 +141,79 @@ export const sendUninstallWarningMail = async ({ receiver, deviceName }: {
})
}
+const taskDoneSender = createMailTemplateSender('taskdone')
+
+export const sendTaskDoneMail = async ({ receiver, child, task }: {
+ receiver: string
+ child: string
+ task: string
+}) => {
+ await taskDoneSender.sendMail({
+ receiver,
+ params: { child, task, mailimprint }
+ })
+}
+
+const deviceLinkedSender = createMailTemplateSender('device-linked-by-mail')
+
+export const sendDeviceLinkedMail = async ({ receiver, deviceName, locale }: {
+ receiver: string
+ deviceName: string
+ locale: string
+}) => {
+ await deviceLinkedSender.sendMail({
+ receiver,
+ params: {
+ subject: locale === 'de' ? 'Gerät hinzugefügt' : 'Device added',
+ preText: locale === 'de' ? 'Soeben wurde das Gerät' : 'The device',
+ deviceName,
+ postText: locale === 'de' ? 'über Ihre E-Mail-Adresse hinzugefügt.' : 'was added using your mail address.',
+ securityText: getMailSecurityText(locale),
+ mailimprint
+ }
+ })
+}
+
+const passwordRecoveryUsedMailSender = createMailTemplateSender('password-recovery-used')
+
+export const sendPasswordRecoveryUsedMail = async ({ receiver, locale }: {
+ receiver: string
+ locale: string
+}) => {
+ await passwordRecoveryUsedMailSender.sendMail({
+ receiver,
+ params: {
+ subject: locale === 'de' ? 'Passwort-Vergessen-Funktion verwendet' : 'Password reset',
+ text: locale === 'de' ?
+ 'Soeben wurde Ihr TimeLimit-Passwort mit der Passwort-Vergessen-Funktion geändert.' :
+ 'Your password was changed using the password reset feature.',
+ securityText: getMailSecurityText(locale),
+ mailimprint
+ }
+ })
+}
+
+const accountDeletedMailSender = createMailTemplateSender('account-deleted')
+
+export const sendAccountDeletedMail = async ({ receiver }: {
+ receiver: string
+}) => {
+ await accountDeletedMailSender.sendMail({
+ receiver,
+ params: {
+ mailimprint
+ }
+ })
+}
+
+function getMailSecurityText (locale: string) {
+ if (locale === 'de') {
+ return 'Achten Sie darauf, dass Ihr Kind/Ihre Kinder keinen Zugang zu der E-Mail-Adresse hat/haben, die Sie bei TimeLimit angegeben haben.'
+ } else {
+ return 'Make sure that your child/children can not access the mail addresss that you use for TimeLimit.'
+ }
+}
+
export function isMailServerBlacklisted (mail: string): boolean {
const parts = mail.split('@')
const domain = parts[parts.length - 1]
@@ -127,6 +255,7 @@ export function sanitizeMailAddress (input: string): string | null {
return null
}
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
const address = (parsed as any).address
if (typeof address !== 'string') {
diff --git a/src/util/random-words.ts b/src/util/random-words.ts
index 01aac25..9875bc6 100644
--- a/src/util/random-words.ts
+++ b/src/util/random-words.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,6 +15,7 @@
* along with this program. If not, see .
*/
+import { randomInt } from 'crypto'
import { readFileSync } from 'fs'
import { range } from 'lodash'
import { resolve } from 'path'
@@ -24,11 +25,11 @@ const wordlist = readFileSync(resolve(__dirname, '../../other/wordlist/de.txt'))
.split('\n')
.filter((item) => item.trim().length > 0)
-const randomWord = () => wordlist[Math.floor(Math.random() * (wordlist.length - 1))]
+const randomWord = () => wordlist[randomInt(wordlist.length)]
export const randomWords = (numberOfWords: number) => (
range(numberOfWords)
- .map((item) => randomWord())
+ .map(() => randomWord())
.join(' ')
)
diff --git a/src/util/ratelimit-taskdonemail.ts b/src/util/ratelimit-taskdonemail.ts
new file mode 100644
index 0000000..350b177
--- /dev/null
+++ b/src/util/ratelimit-taskdonemail.ts
@@ -0,0 +1,63 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2020 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { RateLimiterAbstract, RateLimiterMemory } from 'rate-limiter-flexible'
+
+const individualMailLimitMinute: RateLimiterAbstract = new RateLimiterMemory({
+ keyPrefix: 'timelimit:sendmail-taskdone:individual:minute',
+ points: 1,
+ duration: 60 // 1 minute
+})
+
+const individualMailLimitFiveMinutes: RateLimiterAbstract = new RateLimiterMemory({
+ keyPrefix: 'timelimit:sendmail-taskdone:individual:fiveminutes',
+ points: 3,
+ duration: 60 * 5 // 5 minutes
+})
+
+const individualMailLimitHourly: RateLimiterAbstract = new RateLimiterMemory({
+ keyPrefix: 'timelimit:sendmail-taskdone:individual:hourly',
+ points: 5,
+ duration: 60 * 60 // 1 hour
+})
+
+const individualMailLimitDay: RateLimiterAbstract = new RateLimiterMemory({
+ keyPrefix: 'timelimit:sendmail-taskdone:individual:day',
+ points: 10,
+ duration: 60 * 60 * 24 // 1 day
+})
+
+const checkIndividualMailSendLimit = async (receiver: string) => {
+ await individualMailLimitMinute.consume(receiver)
+ await individualMailLimitFiveMinutes.consume(receiver)
+ await individualMailLimitHourly.consume(receiver)
+ await individualMailLimitDay.consume(receiver)
+}
+
+const checkMailSendLimit = async (receiver: string) => {
+ await checkIndividualMailSendLimit(receiver)
+}
+
+export const canSendTaskDoneMail = async (receiver: string) => {
+ try {
+ await checkMailSendLimit(receiver)
+
+ return true
+ } catch (ex) {
+ return false
+ }
+}
diff --git a/src/util/token.ts b/src/util/token.ts
index 39f683a..14fea1e 100644
--- a/src/util/token.ts
+++ b/src/util/token.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,22 +15,26 @@
* along with this program. If not, see .
*/
-import * as TokenGenerator from 'tokgen'
+import { randomInt } from 'crypto'
import { ValidationException } from '../exception'
-const authTokenGenerator = new TokenGenerator({
- length: 32,
- chars: 'a-zA-Z0-9'
-})
+const defaultAlphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
-export const generateAuthToken = () => authTokenGenerator.generate()
+function randomString(chars: string, length: number) {
+ let result = ''
-const idWithinFamilyGenerator = new TokenGenerator({
- length: 6,
- chars: 'a-zA-Z0-9'
-})
+ for (let i = 0; i < length; i++) {
+ result += chars[randomInt(chars.length)]
+ }
-export const generateIdWithinFamily = () => idWithinFamilyGenerator.generate()
+ if (result.length !== length) throw new Error()
+
+ return result
+}
+
+export const generateAuthToken = randomString.bind(null, defaultAlphabet, 32)
+
+export const generateIdWithinFamily = randomString.bind(null, defaultAlphabet, 6)
export const isIdWithinFamily = (id: string) => id.length === 6 && /^[a-zA-Z0-9]+$/.test(id)
export const assertIdWithinFamily = (id: string) => {
if (!isIdWithinFamily(id)) {
@@ -41,23 +45,9 @@ export const assertIdWithinFamily = (id: string) => {
}
}
-const versionIdGenerator = new TokenGenerator({
- length: 4,
- chars: 'a-zA-Z0-9'
-})
+export const generateVersionId = randomString.bind(null, defaultAlphabet, 4)
-export const generateVersionId = () => versionIdGenerator.generate()
+export const isVersionId = (id: string) => id.length === 4 && /^[a-zA-Z0-9]+$/.test(id)
-const familyIdGenerator = new TokenGenerator({
- length: 10,
- chars: 'a-zA-Z0-9'
-})
-
-export const generateFamilyId = () => familyIdGenerator.generate()
-
-const purchaseIdGenerator = new TokenGenerator({
- length: 10,
- chars: 'a-zA-Z0-9'
-})
-
-export const generatePurchaseId = () => purchaseIdGenerator.generate()
+export const generateFamilyId = randomString.bind(null, defaultAlphabet, 10)
+export const generatePurchaseId = randomString.bind(null, defaultAlphabet, 10)
diff --git a/src/util/u2fsignature.ts b/src/util/u2fsignature.ts
new file mode 100644
index 0000000..08c5e35
--- /dev/null
+++ b/src/util/u2fsignature.ts
@@ -0,0 +1,52 @@
+/*
+ * server component for the TimeLimit App
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { createVerify, createPublicKey, createHash } from 'crypto'
+
+export function isU2fSignatureValid({
+ u2fRawResponse, applicationId, challenge, publicKey
+}: {
+ u2fRawResponse: Buffer
+ applicationId: Buffer
+ challenge: Buffer
+ publicKey: Buffer
+}): boolean {
+ if (u2fRawResponse.length < 5) return false
+ if (publicKey.length !== 65 || publicKey.readInt8(0) !== 4) return false
+
+ const publicKeyObject = createPublicKey({
+ key: Buffer.concat([
+ Buffer.from('MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgA=', 'base64'), publicKey
+ ]),
+ format: 'der',
+ type: 'spki'
+ })
+
+ const verifier = createVerify('SHA256')
+
+ verifier.update(applicationId)
+ verifier.update(u2fRawResponse.slice(0, 5))
+ verifier.update(challenge)
+
+ return verifier.verify(publicKeyObject, u2fRawResponse.slice(5))
+}
+
+export function calculateApplicationId(url: string): Buffer {
+ return createHash('sha256')
+ .update(Buffer.from(url, 'utf8'))
+ .digest()
+}
diff --git a/src/websocket/index.ts b/src/websocket/index.ts
index 014304b..d8179a1 100644
--- a/src/websocket/index.ts
+++ b/src/websocket/index.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,8 +15,8 @@
* along with this program. If not, see .
*/
-import * as EventEmitter from 'events'
-import * as io from 'socket.io'
+import { EventEmitter } from 'events'
+import { Server } from 'socket.io'
import { ConnectedDevicesManager, VisibleConnectedDevicesManager } from '../connected-devices'
import { Database } from '../database'
import { deviceByAuthTokenRoom } from './rooms'
@@ -25,7 +25,7 @@ export const createWebsocketHandler = ({ connectedDevicesManager, database }: {
connectedDevicesManager: VisibleConnectedDevicesManager
database: Database
}): {
- websocketServer: io.Server
+ websocketServer: Server
websocketApi: WebsocketApi
} => {
const events = new EventEmitter()
@@ -37,14 +37,16 @@ export const createWebsocketHandler = ({ connectedDevicesManager, database }: {
const eventTriggerImportantSyncForAll = 'triggerimportantsyncforall'
let socketCounter = 0
- const server = io()
+ const server = new Server({
+ allowEIO3: true
+ })
server.on('connection', (socket) => {
socketCounter++
socket.on('disconnect', () => socketCounter--)
- socket.on('devicelogin', (deviceAuthToken: any, ack: any) => {
- socket.leaveAll()
+ socket.on('devicelogin', (deviceAuthToken: unknown, ack: unknown) => {
+ socket.rooms.forEach((room) => socket.leave(room))
if (typeof deviceAuthToken !== 'string') {
return
@@ -93,7 +95,7 @@ export const createWebsocketHandler = ({ connectedDevicesManager, database }: {
shutdown()
})
}
- })().catch((ex) => { /* ignore */ })
+ })().catch(() => { /* ignore */ })
if (typeof ack === 'function') {
ack()
diff --git a/src/worker/delete-deprecated-purchases.ts b/src/worker/delete-deprecated-purchases.ts
index 8469999..35928d5 100644
--- a/src/worker/delete-deprecated-purchases.ts
+++ b/src/worker/delete-deprecated-purchases.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -25,7 +25,11 @@ export function initDeleteDeprecatedPurchasesWorker ({ database, websocket }: {
websocket: WebsocketApi
}) {
function doWorkSafe () {
- deleteDeprecatedPurchases({ database, websocket }).catch((ex) => {
+ console.log('deleting deprecated purchases now')
+
+ deleteDeprecatedPurchases({ database, websocket }).then(() => {
+ console.log('finished deleting deprecated purchases')
+ }).catch((ex) => {
console.warn('error deleting deprecated purchases', ex)
})
}
@@ -44,7 +48,7 @@ async function deleteDeprecatedPurchases ({ database, websocket }: {
websocket: WebsocketApi
}) {
await database.transaction(async (transaction) => {
- const affectedFamilyIds = await database.family.findAll({
+ const affectedFamilyIds = (await database.family.findAll({
where: {
hasFullVersion: true,
fullVersionUntil: {
@@ -53,15 +57,14 @@ async function deleteDeprecatedPurchases ({ database, websocket }: {
},
attributes: ['familyId'],
transaction,
- lock: Sequelize.Transaction.LOCK.UPDATE,
limit: 100
- }).map((item) => item.familyId)
+ })).map((item) => item.familyId)
await database.family.update({
hasFullVersion: false
}, {
where: {
- familyid: {
+ familyId: {
[Sequelize.Op.in]: affectedFamilyIds
}
},
@@ -74,7 +77,8 @@ async function deleteDeprecatedPurchases ({ database, websocket }: {
sourceDeviceId: null,
database,
websocket,
- isImportant: true,
+ generalLevel: 2,
+ targetedLevels: new Map(),
transaction
})
}
diff --git a/src/worker/delete-old-families.ts b/src/worker/delete-old-families.ts
index f15116d..101a615 100644
--- a/src/worker/delete-old-families.ts
+++ b/src/worker/delete-old-families.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -22,7 +22,11 @@ export function initDeleteOldFamiliesWorker ({ database }: {
database: Database
}) {
function doWorkSafe () {
- deleteOldFamilies(database).catch((ex) => {
+ console.log('deleting old families now')
+
+ deleteOldFamilies(database).then(() => {
+ console.log('finished deleting old families')
+ }).catch((ex) => {
console.warn('error deleting old families', ex)
})
}
diff --git a/src/worker/delete-old-tokens.ts b/src/worker/delete-old-tokens.ts
index 010d6f3..ac2f901 100644
--- a/src/worker/delete-old-tokens.ts
+++ b/src/worker/delete-old-tokens.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 Jonas Lochmann
+ * Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -22,7 +22,11 @@ export function initDeleteOldTokensWorker ({ database }: {
database: Database
}) {
function doWorkSafe () {
- deleteOldTokens({ database }).catch((ex) => {
+ console.log('deleting old tokens now')
+
+ deleteOldTokens({ database }).then(() => {
+ console.log('finished deleting old tokens')
+ }).catch((ex) => {
console.warn('error deleting old tokens', ex)
})
}
@@ -67,4 +71,12 @@ async function deleteOldTokens ({ database }: {
transaction
})
})
+
+ await database.deviceDhKey.destroy({
+ where: {
+ expireAt: {
+ [Sequelize.Op.lt]: Date.now().toString()
+ }
+ }
+ })
}
diff --git a/src/worker/delete-old-used-times.ts b/src/worker/delete-old-used-times.ts
index e9c309c..ca47d5c 100644
--- a/src/worker/delete-old-used-times.ts
+++ b/src/worker/delete-old-used-times.ts
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
- * Copyright (C) 2019 - 2020 Jonas Lochmann
+ * Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -24,7 +24,11 @@ export function initDeleteOldUsedTimesWorker ({ database }: {
database: Database
}) {
function doWorkSafe () {
- deleteOldUsedTimes({ database }).catch((ex) => {
+ console.log('deleting old used times now')
+
+ deleteOldUsedTimes({ database }).then(() => {
+ console.log('finished deleting old used times')
+ }).catch((ex) => {
console.warn('error deleting old used times', ex)
})
}
@@ -45,7 +49,7 @@ async function deleteOldUsedTimes ({ database }: {
await database.transaction(async (transaction) => {
// get matching categories
- const categoriesToCleanUpOne = await database.usedTime.findAll({
+ const categoriesToCleanUpOne = (await database.usedTime.findAll({
transaction,
where: {
lastUpdate: {
@@ -58,12 +62,12 @@ async function deleteOldUsedTimes ({ database }: {
],
limit: 1000,
order: [['lastUpdate', 'ASC']]
- }).map((item) => ({
+ })).map((item) => ({
familyId: item.familyId,
categoryId: item.categoryId
}))
- const categoriesToCleanUpTwo = await database.sessionDuration.findAll({
+ const categoriesToCleanUpTwo = (await database.sessionDuration.findAll({
transaction,
where: {
roundedLastUpdate: {
@@ -76,7 +80,7 @@ async function deleteOldUsedTimes ({ database }: {
],
limit: 1000,
order: [['roundedLastUpdate', 'ASC']]
- }).map((item) => ({
+ })).map((item) => ({
familyId: item.familyId,
categoryId: item.categoryId
}))
diff --git a/tsconfig.json b/tsconfig.json
index 74c283a..16846bb 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -11,7 +11,8 @@
"noUnusedParameters": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
- "sourceMap": true
+ "sourceMap": true,
+ "skipLibCheck": true
},
"include": [
"./src/**/*"
diff --git a/tslint.json b/tslint.json
deleted file mode 100644
index 4a21430..0000000
--- a/tslint.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "defaultSeverity": "error",
- "extends": [
- "tslint-config-standard"
- ],
- "jsRules": {},
- "rules": {
- "await-promise": [true, "Bluebird"],
- "ordered-imports": true
- },
- "rulesDirectory": []
-}