Compare commits

...
13 Commits
44 changed files with 2875 additions and 2878 deletions
-3
View File
@@ -1,3 +0,0 @@
node_modules
build
scripts
-14
View File
@@ -1,14 +0,0 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: [
'@typescript-eslint',
],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
],
env: {
node: true
}
};
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:16-alpine
FROM node:24-alpine
# Create app directories
RUN mkdir -p /usr/src/app
+2 -1
View File
@@ -96,10 +96,11 @@ Use this to unlock all features for one user for a specified duration.
### request
request properties: ``purchaseToken`` and ``purchaseId``
request properties: ``purchaseToken``, ``purchaseId`` and ``dryRun``
- ``purchasetoken`` is a string which the client shows at the purchase screen
- ``purchaseId`` is the ID that is used at the bill
- ``dryRun`` is a boolean; setting true will skip the actual unlocking
### response
+6
View File
@@ -130,6 +130,8 @@
* [SerializedMarkTaskPendingAction](./serializedapplogicaction-definitions-serializedmarktaskpendingaction.md) `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedMarkTaskPendingAction`
* [SerializedPingAction](./serializedapplogicaction-definitions-serializedpingaction.md) `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction`
* [SerializedRemoveCategoryAppsAction](./serializedparentaction-definitions-serializedremovecategoryappsaction.md) `https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveCategoryAppsAction`
* [SerializedRemoveInstalledAppsAction](./serializedapplogicaction-definitions-serializedremoveinstalledappsaction.md) `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedRemoveInstalledAppsAction`
@@ -238,6 +240,8 @@
* [ServerKeyResponse](./serverdatastatus-definitions-serverkeyresponse.md) `https://timelimit.io/ServerDataStatus#/definitions/ServerKeyResponse`
* [ServerPing](./serverdatastatus-definitions-serverping.md) `https://timelimit.io/ServerDataStatus#/definitions/ServerPing`
* [ServerSessionDurationItem](./serverdatastatus-definitions-serversessiondurationitem.md) `https://timelimit.io/ServerDataStatus#/definitions/ServerSessionDurationItem`
* [ServerTimeLimitRule](./serverdatastatus-definitions-servertimelimitrule.md) `https://timelimit.io/ServerDataStatus#/definitions/ServerTimeLimitRule`
@@ -346,6 +350,8 @@
* [Untitled array in ServerDataStatus](./serverdatastatus-properties-kr.md) `https://timelimit.io/ServerDataStatus#/properties/kr`
* [Untitled array in ServerDataStatus](./serverdatastatus-properties-pings.md) `https://timelimit.io/ServerDataStatus#/properties/pings`
* [Untitled array in ServerDataStatus](./serverdatastatus-definitions-u2fdata-properties-d.md) `https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/d`
## Version Note
@@ -21,6 +21,9 @@
{
"$ref": "#/definitions/SerializedMarkTaskPendingAction"
},
{
"$ref": "#/definitions/SerializedPingAction"
},
{
"$ref": "#/definitions/SerializedUpdateInstalledAppsAction"
},
@@ -309,6 +312,43 @@
],
"title": "SerializedMarkTaskPendingAction"
},
"SerializedPingAction": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"PING"
]
},
"deviceId": {
"type": "string"
},
"event": {
"$ref": "#/definitions/PingEvent"
},
"token": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"deviceId",
"event",
"token",
"type"
],
"title": "SerializedPingAction"
},
"PingEvent": {
"enum": [
"clear",
"ping",
"pong"
],
"type": "string",
"title": "PingEvent"
},
"SerializedUpdateInstalledAppsAction": {
"type": "object",
"properties": {
+31
View File
@@ -67,6 +67,12 @@
"$ref": "#/definitions/ServerKeyResponse"
}
},
"pings": {
"type": "array",
"items": {
"$ref": "#/definitions/ServerPing"
}
},
"dh": {
"$ref": "#/definitions/ServerDhKey"
},
@@ -927,6 +933,31 @@
],
"title": "ServerKeyResponse"
},
"ServerPing": {
"type": "object",
"properties": {
"deviceId": {
"type": "string"
},
"token": {
"type": "string"
},
"type": {
"enum": [
"ping",
"pong"
],
"type": "string"
}
},
"additionalProperties": false,
"required": [
"deviceId",
"token",
"type"
],
"title": "ServerPing"
},
"ServerDhKey": {
"type": "object",
"properties": {
@@ -0,0 +1,25 @@
# PingEvent Schema
```txt
https://timelimit.io/SerializedAppLogicAction#/definitions/PingEvent
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :---------------------------------------------------------------------------------------------------- |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedAppLogicAction.schema.json\*](SerializedAppLogicAction.schema.json "open original schema") |
## PingEvent Type
`string` ([PingEvent](serializedapplogicaction-definitions-pingevent.md))
## PingEvent Constraints
**enum**: the value of this property must be equal to one of the following values:
| Value | Explanation |
| :-------- | :---------- |
| `"clear"` | |
| `"ping"` | |
| `"pong"` | |
@@ -0,0 +1,15 @@
# Untitled string in SerializedAppLogicAction Schema
```txt
https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/deviceId
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :---------------------------------------------------------------------------------------------------- |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedAppLogicAction.schema.json\*](SerializedAppLogicAction.schema.json "open original schema") |
## deviceId Type
`string`
@@ -0,0 +1,25 @@
# PingEvent Schema
```txt
https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/event
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :---------------------------------------------------------------------------------------------------- |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedAppLogicAction.schema.json\*](SerializedAppLogicAction.schema.json "open original schema") |
## event Type
`string` ([PingEvent](serializedapplogicaction-definitions-serializedpingaction-properties-pingevent.md))
## event Constraints
**enum**: the value of this property must be equal to one of the following values:
| Value | Explanation |
| :-------- | :---------- |
| `"clear"` | |
| `"ping"` | |
| `"pong"` | |
@@ -0,0 +1,15 @@
# Untitled string in SerializedAppLogicAction Schema
```txt
https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/token
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :---------------------------------------------------------------------------------------------------- |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedAppLogicAction.schema.json\*](SerializedAppLogicAction.schema.json "open original schema") |
## token Type
`string`
@@ -0,0 +1,23 @@
# Untitled string in SerializedAppLogicAction Schema
```txt
https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/type
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :---------------------------------------------------------------------------------------------------- |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedAppLogicAction.schema.json\*](SerializedAppLogicAction.schema.json "open original schema") |
## type Type
`string`
## type Constraints
**enum**: the value of this property must be equal to one of the following values:
| Value | Explanation |
| :------- | :---------- |
| `"PING"` | |
@@ -0,0 +1,114 @@
# SerializedPingAction Schema
```txt
https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :----------- | :---------------- | :-------------------- | :------------------ | :---------------------------------------------------------------------------------------------------- |
| Can be instantiated | No | Unknown status | No | Forbidden | Forbidden | none | [SerializedAppLogicAction.schema.json\*](SerializedAppLogicAction.schema.json "open original schema") |
## SerializedPingAction Type
`object` ([SerializedPingAction](serializedapplogicaction-definitions-serializedpingaction.md))
# SerializedPingAction Properties
| Property | Type | Required | Nullable | Defined by |
| :-------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [type](#type) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/type") |
| [deviceId](#deviceid) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-deviceid.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/deviceId") |
| [event](#event) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-pingevent.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/event") |
| [token](#token) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-token.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/token") |
## type
`type`
* is required
* Type: `string`
* cannot be null
* defined in: [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/type")
### type Type
`string`
### type Constraints
**enum**: the value of this property must be equal to one of the following values:
| Value | Explanation |
| :------- | :---------- |
| `"PING"` | |
## deviceId
`deviceId`
* is required
* Type: `string`
* cannot be null
* defined in: [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-deviceid.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/deviceId")
### deviceId Type
`string`
## event
`event`
* is required
* Type: `string` ([PingEvent](serializedapplogicaction-definitions-serializedpingaction-properties-pingevent.md))
* cannot be null
* defined in: [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-pingevent.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/event")
### event Type
`string` ([PingEvent](serializedapplogicaction-definitions-serializedpingaction-properties-pingevent.md))
### event Constraints
**enum**: the value of this property must be equal to one of the following values:
| Value | Explanation |
| :-------- | :---------- |
| `"clear"` | |
| `"ping"` | |
| `"pong"` | |
## token
`token`
* is required
* Type: `string`
* cannot be null
* defined in: [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-token.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/token")
### token Type
`string`
+127 -9
View File
@@ -30,6 +30,8 @@ any of
* [SerializedMarkTaskPendingAction](serializedapplogicaction-definitions-serializedmarktaskpendingaction.md "check type definition")
* [SerializedPingAction](serializedapplogicaction-definitions-serializedpingaction.md "check type definition")
* [SerializedUpdateInstalledAppsAction](serializedapplogicaction-definitions-serializedupdateinstalledappsaction.md "check type definition")
* [SerializedRemoveInstalledAppsAction](serializedapplogicaction-definitions-serializedremoveinstalledappsaction.md "check type definition")
@@ -688,6 +690,122 @@ Reference this group by using
`string`
## Definitions group SerializedPingAction
Reference this group by using
```json
{"$ref":"https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction"}
```
| Property | Type | Required | Nullable | Defined by |
| :-------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [type](#type-7) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/type") |
| [deviceId](#deviceid) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-deviceid.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/deviceId") |
| [event](#event) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-pingevent.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/event") |
| [token](#token) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-token.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/token") |
### type
`type`
* is required
* Type: `string`
* cannot be null
* defined in: [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/type")
#### type Type
`string`
#### type Constraints
**enum**: the value of this property must be equal to one of the following values:
| Value | Explanation |
| :------- | :---------- |
| `"PING"` | |
### deviceId
`deviceId`
* is required
* Type: `string`
* cannot be null
* defined in: [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-deviceid.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/deviceId")
#### deviceId Type
`string`
### event
`event`
* is required
* Type: `string` ([PingEvent](serializedapplogicaction-definitions-serializedpingaction-properties-pingevent.md))
* cannot be null
* defined in: [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-pingevent.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/event")
#### event Type
`string` ([PingEvent](serializedapplogicaction-definitions-serializedpingaction-properties-pingevent.md))
#### event Constraints
**enum**: the value of this property must be equal to one of the following values:
| Value | Explanation |
| :-------- | :---------- |
| `"clear"` | |
| `"ping"` | |
| `"pong"` | |
### token
`token`
* is required
* Type: `string`
* cannot be null
* defined in: [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedpingaction-properties-token.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedPingAction/properties/token")
#### token Type
`string`
## Definitions group PingEvent
Reference this group by using
```json
{"$ref":"https://timelimit.io/SerializedAppLogicAction#/definitions/PingEvent"}
```
| Property | Type | Required | Nullable | Defined by |
| :------- | :--- | :------- | :------- | :--------- |
## Definitions group SerializedUpdateInstalledAppsAction
Reference this group by using
@@ -698,7 +816,7 @@ Reference this group by using
| Property | Type | Required | Nullable | Defined by |
| :-------------- | :-------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [type](#type-7) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdateinstalledappsaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateInstalledAppsAction/properties/type") |
| [type](#type-8) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdateinstalledappsaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateInstalledAppsAction/properties/type") |
| [b](#b) | `string` | Optional | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdateinstalledappsaction-properties-b.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateInstalledAppsAction/properties/b") |
| [d](#d-1) | `string` | Optional | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdateinstalledappsaction-properties-d.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateInstalledAppsAction/properties/d") |
| [w](#w) | `boolean` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdateinstalledappsaction-properties-w.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateInstalledAppsAction/properties/w") |
@@ -793,7 +911,7 @@ Reference this group by using
| Property | Type | Required | Nullable | Defined by |
| :---------------------------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [type](#type-8) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedremoveinstalledappsaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedRemoveInstalledAppsAction/properties/type") |
| [type](#type-9) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedremoveinstalledappsaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedRemoveInstalledAppsAction/properties/type") |
| [packageNames](#packagenames) | `array` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedremoveinstalledappsaction-properties-packagenames.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedRemoveInstalledAppsAction/properties/packageNames") |
### type
@@ -850,9 +968,9 @@ Reference this group by using
| Property | Type | Required | Nullable | Defined by |
| :-------------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [type](#type-9) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedsendkeyrequestaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSendKeyRequestAction/properties/type") |
| [type](#type-10) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedsendkeyrequestaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSendKeyRequestAction/properties/type") |
| [dsn](#dsn-1) | `number` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedsendkeyrequestaction-properties-dsn.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSendKeyRequestAction/properties/dsn") |
| [deviceId](#deviceid) | `string` | Optional | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedsendkeyrequestaction-properties-deviceid.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSendKeyRequestAction/properties/deviceId") |
| [deviceId](#deviceid-1) | `string` | Optional | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedsendkeyrequestaction-properties-deviceid.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSendKeyRequestAction/properties/deviceId") |
| [categoryId](#categoryid-1) | `string` | Optional | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedsendkeyrequestaction-properties-categoryid.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSendKeyRequestAction/properties/categoryId") |
| [dataType](#datatype) | `number` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedsendkeyrequestaction-properties-datatype.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSendKeyRequestAction/properties/dataType") |
| [tempKey](#tempkey-1) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedsendkeyrequestaction-properties-tempkey.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSendKeyRequestAction/properties/tempKey") |
@@ -1002,7 +1120,7 @@ Reference this group by using
| Property | Type | Required | Nullable | Defined by |
| :--------------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [type](#type-10) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedsignoutatdeviceaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSignOutAtDeviceAction/properties/type") |
| [type](#type-11) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedsignoutatdeviceaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSignOutAtDeviceAction/properties/type") |
### type
@@ -1040,7 +1158,7 @@ Reference this group by using
| Property | Type | Required | Nullable | Defined by |
| :--------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [type](#type-11) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serialiezdtrieddisablingdeviceadminaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerialiezdTriedDisablingDeviceAdminAction/properties/type") |
| [type](#type-12) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serialiezdtrieddisablingdeviceadminaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerialiezdTriedDisablingDeviceAdminAction/properties/type") |
### type
@@ -1078,7 +1196,7 @@ Reference this group by using
| Property | Type | Required | Nullable | Defined by |
| :-------------------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [type](#type-12) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdateappactivitiesaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateAppActivitiesAction/properties/type") |
| [type](#type-13) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdateappactivitiesaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateAppActivitiesAction/properties/type") |
| [removed](#removed) | `array` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdateappactivitiesaction-properties-removed.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateAppActivitiesAction/properties/removed") |
| [updatedOrAdded](#updatedoradded) | `array` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdateappactivitiesaction-properties-updatedoradded.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateAppActivitiesAction/properties/updatedOrAdded") |
@@ -1230,7 +1348,7 @@ Reference this group by using
| Property | Type | Required | Nullable | Defined by |
| :---------------------------------------------------------- | :-------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [type](#type-13) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdatedevicestatusaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateDeviceStatusAction/properties/type") |
| [type](#type-14) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdatedevicestatusaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateDeviceStatusAction/properties/type") |
| [protectionLevel](#protectionlevel) | `string` | Optional | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdatedevicestatusaction-properties-protectionlevel.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateDeviceStatusAction/properties/protectionLevel") |
| [usageStats](#usagestats) | `string` | Optional | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdatedevicestatusaction-properties-usagestats.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateDeviceStatusAction/properties/usageStats") |
| [notificationAccess](#notificationaccess) | `string` | Optional | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializedupdatedevicestatusaction-properties-notificationaccess.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUpdateDeviceStatusAction/properties/notificationAccess") |
@@ -1518,7 +1636,7 @@ Reference this group by using
| Property | Type | Required | Nullable | Defined by |
| :--------------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [type](#type-14) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializeduploaddevicepublickeyaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUploadDevicePublicKeyAction/properties/type") |
| [type](#type-15) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializeduploaddevicepublickeyaction-properties-type.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUploadDevicePublicKeyAction/properties/type") |
| [key](#key) | `string` | Required | cannot be null | [SerializedAppLogicAction](serializedapplogicaction-definitions-serializeduploaddevicepublickeyaction-properties-key.md "https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedUploadDevicePublicKeyAction/properties/key") |
### type
@@ -0,0 +1,15 @@
# Untitled string in ServerDataStatus Schema
```txt
https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/deviceId
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------ |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [ServerDataStatus.schema.json\*](ServerDataStatus.schema.json "open original schema") |
## deviceId Type
`string`
@@ -0,0 +1,15 @@
# Untitled string in ServerDataStatus Schema
```txt
https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/token
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------ |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [ServerDataStatus.schema.json\*](ServerDataStatus.schema.json "open original schema") |
## token Type
`string`
@@ -0,0 +1,24 @@
# Untitled string in ServerDataStatus Schema
```txt
https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/type
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------ |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [ServerDataStatus.schema.json\*](ServerDataStatus.schema.json "open original schema") |
## type Type
`string`
## type Constraints
**enum**: the value of this property must be equal to one of the following values:
| Value | Explanation |
| :------- | :---------- |
| `"ping"` | |
| `"pong"` | |
@@ -0,0 +1,86 @@
# ServerPing Schema
```txt
https://timelimit.io/ServerDataStatus#/definitions/ServerPing
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :----------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------ |
| Can be instantiated | No | Unknown status | No | Forbidden | Forbidden | none | [ServerDataStatus.schema.json\*](ServerDataStatus.schema.json "open original schema") |
## ServerPing Type
`object` ([ServerPing](serverdatastatus-definitions-serverping.md))
# ServerPing Properties
| Property | Type | Required | Nullable | Defined by |
| :-------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [deviceId](#deviceid) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverping-properties-deviceid.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/deviceId") |
| [token](#token) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverping-properties-token.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/token") |
| [type](#type) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverping-properties-type.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/type") |
## deviceId
`deviceId`
* is required
* Type: `string`
* cannot be null
* defined in: [ServerDataStatus](serverdatastatus-definitions-serverping-properties-deviceid.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/deviceId")
### deviceId Type
`string`
## token
`token`
* is required
* Type: `string`
* cannot be null
* defined in: [ServerDataStatus](serverdatastatus-definitions-serverping-properties-token.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/token")
### token Type
`string`
## type
`type`
* is required
* Type: `string`
* cannot be null
* defined in: [ServerDataStatus](serverdatastatus-definitions-serverping-properties-type.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/type")
### type Type
`string`
### type Constraints
**enum**: the value of this property must be equal to one of the following values:
| Value | Explanation |
| :------- | :---------- |
| `"ping"` | |
| `"pong"` | |
@@ -0,0 +1,15 @@
# Untitled array in ServerDataStatus Schema
```txt
https://timelimit.io/ServerDataStatus#/properties/pings
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------ |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [ServerDataStatus.schema.json\*](ServerDataStatus.schema.json "open original schema") |
## pings Type
`object[]` ([ServerPing](serverdatastatus-definitions-serverping.md))
+96
View File
@@ -30,6 +30,7 @@ https://timelimit.io/ServerDataStatus
| [users](#users) | `object` | Optional | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serveruserlist.md "https://timelimit.io/ServerDataStatus#/properties/users") |
| [krq](#krq) | `array` | Optional | cannot be null | [ServerDataStatus](serverdatastatus-properties-krq.md "https://timelimit.io/ServerDataStatus#/properties/krq") |
| [kr](#kr) | `array` | Optional | cannot be null | [ServerDataStatus](serverdatastatus-properties-kr.md "https://timelimit.io/ServerDataStatus#/properties/kr") |
| [pings](#pings) | `array` | Optional | cannot be null | [ServerDataStatus](serverdatastatus-properties-pings.md "https://timelimit.io/ServerDataStatus#/properties/pings") |
| [dh](#dh) | `object` | Optional | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverdhkey.md "https://timelimit.io/ServerDataStatus#/properties/dh") |
| [u2f](#u2f) | `object` | Optional | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fdata.md "https://timelimit.io/ServerDataStatus#/properties/u2f") |
| [fullVersion](#fullversion) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-properties-fullversion.md "https://timelimit.io/ServerDataStatus#/properties/fullVersion") |
@@ -252,6 +253,24 @@ https://timelimit.io/ServerDataStatus
`object[]` ([ServerKeyResponse](serverdatastatus-definitions-serverkeyresponse.md))
## pings
`pings`
* is optional
* Type: `object[]` ([ServerPing](serverdatastatus-definitions-serverping.md))
* cannot be null
* defined in: [ServerDataStatus](serverdatastatus-properties-pings.md "https://timelimit.io/ServerDataStatus#/properties/pings")
### pings Type
`object[]` ([ServerPing](serverdatastatus-definitions-serverping.md))
## dh
@@ -3449,6 +3468,83 @@ Reference this group by using
`string`
## Definitions group ServerPing
Reference this group by using
```json
{"$ref":"https://timelimit.io/ServerDataStatus#/definitions/ServerPing"}
```
| Property | Type | Required | Nullable | Defined by |
| :---------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [deviceId](#deviceid-4) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverping-properties-deviceid.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/deviceId") |
| [token](#token) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverping-properties-token.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/token") |
| [type](#type-2) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-serverping-properties-type.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/type") |
### deviceId
`deviceId`
* is required
* Type: `string`
* cannot be null
* defined in: [ServerDataStatus](serverdatastatus-definitions-serverping-properties-deviceid.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/deviceId")
#### deviceId Type
`string`
### token
`token`
* is required
* Type: `string`
* cannot be null
* defined in: [ServerDataStatus](serverdatastatus-definitions-serverping-properties-token.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/token")
#### token Type
`string`
### type
`type`
* is required
* Type: `string`
* cannot be null
* defined in: [ServerDataStatus](serverdatastatus-definitions-serverping-properties-type.md "https://timelimit.io/ServerDataStatus#/definitions/ServerPing/properties/type")
#### type Type
`string`
#### type Constraints
**enum**: the value of this property must be equal to one of the following values:
| Value | Explanation |
| :------- | :---------- |
| `"ping"` | |
| `"pong"` | |
## Definitions group ServerDhKey
Reference this group by using
+18
View File
@@ -0,0 +1,18 @@
// @ts-check
import eslint from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
{
ignores: ['build', 'scripts']
},
{
rules: {
'@typescript-eslint/no-unused-vars': ['warn', { caughtErrors: 'none' }]
}
}
)
+1725 -2806
View File
File diff suppressed because it is too large Load Diff
+9 -10
View File
@@ -6,10 +6,10 @@
"scripts": {
"start": "node ./build/index.js",
"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",
"lint": "eslint .",
"lint:fix": "eslint . --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:clean": "rm -rf build",
"build:json": "node ./scripts/build-schemas.js",
"build:ts": "tsc",
"build:doc": "npm run build:doc:json",
@@ -30,6 +30,7 @@
"homepage": "https://gitlab.com/timelimit.io/timelimit-server-2018#README",
"devDependencies": {
"@adobe/jsonschema2md": "^8.0.8",
"@eslint/js": "^10.0.1",
"@types/basic-auth": "^1.1.3",
"@types/body-parser": "^1.19.0",
"@types/ejs": "^3.1.0",
@@ -38,15 +39,13 @@
"@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",
"eslint": "^10.0.1",
"typescript": "^5.5.4",
"typescript-eslint": "^8.56.0",
"typescript-json-schema": "^0.52.0"
},
"dependencies": {
"ajv": "^7.0.2",
"ajv": "^8.18.0",
"basic-auth": "^2.0.1",
"body-parser": "^1.19.0",
"ejs": "^3.1.5",
@@ -56,7 +55,7 @@
"jose": "^4.9.3",
"lodash": "^4.17.21",
"mariadb": "^2.5.2",
"nodemailer": "^7.0.9",
"nodemailer": "^8.0.4",
"pg": "^8.5.1",
"pg-hstore": "^2.3.3",
"rate-limiter-flexible": "^2.1.15",
@@ -65,6 +64,6 @@
"umzug": "^3.8.1"
},
"optionalDependencies": {
"sqlite3": "^5.0.0"
"sqlite3": "npm:@vscode/sqlite3@^5.1.12-vscode"
}
}
+4 -2
View File
@@ -24,6 +24,8 @@ const { spawnAsync } = require('../process.js')
const { sleep } = require('../sleep.js')
async function startMariadb() {
const osUsername = require('os').userInfo().username
try { await mkdirAsync(tempDir) } catch (ex) {/* ignore */}
const instanceDir = resolve(tempDir, generateShortToken())
@@ -60,12 +62,12 @@ async function startMariadb() {
for (command of commands) {
console.log(command)
await spawnAsync('mysql', ['-S', socketPath, '-u', 'root', '-e', command], { stdio: 'inherit' })
await spawnAsync('mysql', ['-S', socketPath, '-u', osUsername, '-e', command], { stdio: 'inherit' })
}
return {
shutdown: () => {
spawnAsync('mysql', ['-S', socketPath, '-u', 'root', '-e', 'SHUTDOWN;'], { stdio: 'inherit' }).catch((ex) => {
spawnAsync('mysql', ['-S', socketPath, '-u', osUsername, '-e', 'SHUTDOWN;'], { stdio: 'inherit' }).catch((ex) => {
console.warn(ex)
})
},
+1 -1
View File
@@ -58,7 +58,7 @@ async function startPostgres() {
const password = generateToken() // this database accepts anything
await spawnAsync('createuser', ['-h', socketDir, username], { stdio: 'inherit' })
await spawnAsync('createdb', ['-h', socketDir, database], { stdio: 'inherit' })
await spawnAsync('createdb', ['-h', socketDir, '--owner', username, database], { stdio: 'inherit' })
return {
shutdown: () => task.kill('SIGINT'),
+2 -1
View File
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann
* Copyright (C) 2019 - 2026 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,6 +78,7 @@ export { UpdateTimelimitRuleAction } from './updatetimelimitrule'
export { UpdateUserFlagsAction } from './updateuserflags'
export { UpdateUserLimitLoginCategory } from './updateuserlimitlogincategory'
export { MarkTaskPendingAction } from './marktaskpendingaction'
export { PingAction } from './ping'
export { DeleteChildTaskAction } from './deletechildtaskaction'
export { UpdateChildTaskAction } from './updatechildtaskaction'
export { ReviewChildTaskAction } from './reviewchildtaskaction'
+55
View File
@@ -0,0 +1,55 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2026 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 <https://www.gnu.org/licenses/>.
*/
import { AppLogicAction } from './basetypes'
import { assertIdWithinFamily } from './meta/util'
const actionType = 'PingAction'
export class PingAction extends AppLogicAction {
readonly deviceId: string
readonly event: PingEvent
readonly token: string
constructor ({ deviceId, event, token }: {
deviceId: string
event: PingEvent
token: string
}) {
super()
assertIdWithinFamily({ actionType, field: 'deviceId', value: deviceId })
assertIdWithinFamily({ actionType, field: 'token', value: token })
this.deviceId = deviceId
this.event = event
this.token = token
}
static parse = ({ deviceId, event, token }: SerializedPingAction) => (
new PingAction({ deviceId, event, token })
)
}
export interface SerializedPingAction {
type: 'PING'
deviceId: string
event: PingEvent
token: string
}
export type PingEvent = 'ping' | 'pong' | 'clear'
+5 -1
View File
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann
* Copyright (C) 2019 - 2026 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,6 +24,7 @@ import { ForceSyncAction, SerializedForceSyncAction } from '../forcesync'
import { ReplyToKeyRequestAction, SerializedReplyToKeyRequestAction } from '../replytokeyrequest'
import { MarkTaskPendingAction, SerializedMarkTaskPendingAction } from '../marktaskpendingaction'
import { UnknownActionTypeException } from '../meta/exception'
import { PingAction, SerializedPingAction } from '../ping'
import { UpdateInstalledAppsAction, SerializedUpdateInstalledAppsAction } from '../updateinstalledapps'
import { RemoveInstalledAppsAction, SerializedRemoveInstalledAppsAction } from '../removeinstalledapps'
import { SendKeyRequestAction, SerializedSendKeyRequestAction } from '../sendkeyrequest'
@@ -41,6 +42,7 @@ export type SerializedAppLogicAction =
SerializedForceSyncAction |
SerializedReplyToKeyRequestAction |
SerializedMarkTaskPendingAction |
SerializedPingAction |
SerializedUpdateInstalledAppsAction |
SerializedRemoveInstalledAppsAction |
SerializedSendKeyRequestAction |
@@ -65,6 +67,8 @@ export const parseAppLogicAction = (serialized: SerializedAppLogicAction): AppLo
return ReplyToKeyRequestAction.parse(serialized)
} else if (serialized.type === 'MARK_TASK_PENDING') {
return MarkTaskPendingAction.parse(serialized)
} else if (serialized.type === 'PING') {
return PingAction.parse(serialized)
} else if (serialized.type === 'UPDATE_INSTALLED_APPS') {
return UpdateInstalledAppsAction.parse(serialized)
} else if (serialized.type === 'REMOVE_INSTALLED_APPS') {
+14 -10
View File
@@ -140,13 +140,15 @@ export const createAdminRouter = ({ database, websocket, eventHandler }: {
if (
typeof req.body !== 'object' ||
typeof req.body.purchaseToken !== 'string' ||
typeof req.body.purchaseId !== 'string'
typeof req.body.purchaseId !== 'string' ||
typeof req.body.dryRun !== 'boolean'
) {
throw new BadRequest()
}
const purchaseToken: string = req.body.purchaseToken
const purchaseId: string = req.body.purchaseId
const dryRun: boolean = req.body.dryRun
const tokenContent = await verifyIdentitifyToken(purchaseToken)
@@ -250,15 +252,17 @@ export const createAdminRouter = ({ database, websocket, eventHandler }: {
}
}
await addPurchase({
database,
familyId: tokenContent.familyId,
type: 'year',
service: 'directpurchase',
transactionId: purchaseId,
websocket,
transaction
})
if (!dryRun) {
await addPurchase({
database,
familyId: tokenContent.familyId,
type: 'year',
service: 'directpurchase',
transactionId: purchaseId,
websocket,
transaction
})
}
}
return {
+62
View File
@@ -1759,6 +1759,41 @@ const definitions = {
"type"
]
},
"SerializedPingAction": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"PING"
]
},
"deviceId": {
"type": "string"
},
"event": {
"$ref": "#/definitions/PingEvent"
},
"token": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"deviceId",
"event",
"token",
"type"
]
},
"PingEvent": {
"enum": [
"clear",
"ping",
"pong"
],
"type": "string"
},
"SerializedUpdateInstalledAppsAction": {
"type": "object",
"properties": {
@@ -2815,6 +2850,30 @@ const definitions = {
"tempKey"
]
},
"ServerPing": {
"type": "object",
"properties": {
"deviceId": {
"type": "string"
},
"token": {
"type": "string"
},
"type": {
"enum": [
"ping",
"pong"
],
"type": "string"
}
},
"additionalProperties": false,
"required": [
"deviceId",
"token",
"type"
]
},
"ServerDhKey": {
"type": "object",
"properties": {
@@ -3213,6 +3272,9 @@ export const isSerializedAppLogicAction: (value: unknown) => value is Serialized
{
"$ref": "#/definitions/SerializedMarkTaskPendingAction"
},
{
"$ref": "#/definitions/SerializedPingAction"
},
{
"$ref": "#/definitions/SerializedUpdateInstalledAppsAction"
},
+4 -1
View File
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann
* Copyright (C) 2019 - 2026 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,6 +33,7 @@ import { createKeyResponseModel, KeyResponseModelStatic } from './keyresponse'
import { createMailLoginTokenModel, MailLoginTokenModelStatic } from './maillogintoken'
import { createUmzug } from './migration/umzug'
import { createOldDeviceModel, OldDeviceModelStatic } from './olddevice'
import { createPingModel, PingModelStatic } from './ping'
import { createPurchaseModel, PurchaseModelStatic } from './purchase'
import { createSessionDurationModel, SessionDurationModelStatic } from './sessionduration'
import { createTimelimitRuleModel, TimelimitRuleModelStatic } from './timelimitrule'
@@ -61,6 +62,7 @@ export interface Database {
keyResponse: KeyResponseModelStatic
mailLoginToken: MailLoginTokenModelStatic
oldDevice: OldDeviceModelStatic
ping: PingModelStatic
purchase: PurchaseModelStatic
sessionDuration: SessionDurationModelStatic
timelimitRule: TimelimitRuleModelStatic
@@ -97,6 +99,7 @@ const createDatabase = (sequelize: Sequelize.Sequelize): Database => ({
keyResponse: createKeyResponseModel(sequelize),
mailLoginToken: createMailLoginTokenModel(sequelize),
oldDevice: createOldDeviceModel(sequelize),
ping: createPingModel(sequelize),
purchase: createPurchaseModel(sequelize),
sessionDuration: createSessionDurationModel(sequelize),
timelimitRule: createTimelimitRuleModel(sequelize),
@@ -0,0 +1,67 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2026 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 <https://www.gnu.org/licenses/>.
*/
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(
'CREATE TABLE `Pings` ' +
'(`familyId` VARCHAR(10) NOT NULL,' +
'`receiverDeviceId` VARCHAR(6) NOT NULL,' +
'`senderDeviceId` VARCHAR(6) NOT NULL,' +
'`type` INTEGER NOT NULL,' +
'`token` VARCHAR(6) NOT NULL,' +
'PRIMARY KEY (`familyId`, `receiverDeviceId`, `senderDeviceId`, `type`),' +
'FOREIGN KEY (`familyId`, `receiverDeviceId`) REFERENCES `Devices` (`familyId`, `deviceId`) ON UPDATE CASCADE ON DELETE CASCADE,' +
'FOREIGN KEY (`familyId`, `senderDeviceId`) REFERENCES `Devices` (`familyId`, `deviceId`) ON UPDATE CASCADE ON DELETE CASCADE' +
')',
{ transaction }
)
} else {
await sequelize.query(
'CREATE TABLE "Pings" ' +
'("familyId" VARCHAR(10) NOT NULL,' +
'"receiverDeviceId" VARCHAR(6) NOT NULL,' +
'"senderDeviceId" VARCHAR(6) NOT NULL,' +
'"type" INTEGER NOT NULL,' +
'"token" VARCHAR(6) NOT NULL,' +
'PRIMARY KEY ("familyId", "receiverDeviceId", "senderDeviceId", "type"),' +
'FOREIGN KEY ("familyId", "receiverDeviceId") REFERENCES "Devices" ("familyId", "deviceId") ON UPDATE CASCADE ON DELETE CASCADE,' +
'FOREIGN KEY ("familyId", "senderDeviceId") REFERENCES "Devices" ("familyId", "deviceId") ON UPDATE CASCADE ON DELETE CASCADE' +
')',
{ transaction }
)
}
await queryInterface.addIndex('Pings', ['familyId', 'senderDeviceId'], { transaction })
})
}
export async function down (queryInterface: QueryInterface, sequelize: Sequelize) {
await sequelize.transaction({
type: Transaction.TYPES.EXCLUSIVE
}, async (transaction) => {
await queryInterface.dropTable('Pings', { transaction })
})
}
+2 -2
View File
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2024 Jonas Lochmann
* Copyright (C) 2019 - 2026 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,7 +27,7 @@ export const createUmzug = (sequelize: Sequelize) => (
resolve: ({ name, path }) => {
if (!path) throw new Error()
// eslint-disable-next-line @typescript-eslint/no-var-requires
// eslint-disable-next-line @typescript-eslint/no-require-imports
const migration = require(path)
return {
+67
View File
@@ -0,0 +1,67 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2026 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 <https://www.gnu.org/licenses/>.
*/
import * as Sequelize from 'sequelize'
import { familyIdColumn, idWithinFamilyColumn } from './columns'
import { SequelizeAttributes } from './types'
export interface PingAttributes {
familyId: string
receiverDeviceId: string
senderDeviceId: string
type: number
token: string
}
export const types = {
ping: 1,
pong: 2,
all: [1, 2]
}
export type PingModel = Sequelize.Model<PingAttributes> & PingAttributes
export type PingModelStatic = typeof Sequelize.Model & {
new (values?: object, options?: Sequelize.BuildOptions): PingModel;
}
export const attributes: SequelizeAttributes<PingAttributes> = {
familyId: {
...familyIdColumn,
primaryKey: true
},
receiverDeviceId: {
...idWithinFamilyColumn,
primaryKey: true
},
senderDeviceId: {
...idWithinFamilyColumn,
primaryKey: true
},
type: {
type: Sequelize.INTEGER,
allowNull: false,
validate: {
isIn: [types.all]
},
primaryKey: true
},
token: {
...idWithinFamilyColumn
}
}
export const createPingModel = (sequelize: Sequelize.Sequelize): PingModelStatic => sequelize.define('Ping', attributes) as PingModelStatic
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2023 Jonas Lochmann
* Copyright (C) 2019 - 2026 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
@@ -89,7 +89,6 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
addUsedTimeForADifferentUserThanTheCurrentUserOfTheDevice = true
}
// eslint-disable-next-line no-inner-declarations
async function handle (start: number, end: number) {
const lengthInMinutes = (end - start) + 1
const lengthInMs = lengthInMinutes * 1000 * 60
@@ -215,10 +214,10 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
const fittingDurationItemsLastUsageFiltered =
hasTrustedTimestamp ?
fittingDurationItems.filter((it) => {
fittingDurationItems.filter((it) => (
action.trustedTimestamp - item.timeToAdd <=
parseInt(it.lastUsage, 10) + it.sessionPauseDuration - tolerance
}) : fittingDurationItems
)) : fittingDurationItems
return fittingDurationItemsLastUsageFiltered
.map((it) => it.lastSessionDuration)
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann
* Copyright (C) 2019 - 2026 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 {
FinishKeyRequestAction,
ForceSyncAction,
MarkTaskPendingAction,
PingAction,
ReplyToKeyRequestAction,
RemoveInstalledAppsAction,
SendKeyRequestAction,
@@ -41,6 +42,7 @@ import { dispatchAddUsedTimeVersion2 } from './addusedtime2'
import { dispatchFinishKeyRequestAction } from './finishkeyrequest'
import { dispatchForceSyncAction } from './forcesync'
import { dispatchMarkTaskPendingAction } from './marktaskpendingaction'
import { dispatchPingAction } from './ping'
import { dispatchReplyToKeyRequestAction } from './replytokeyrequest'
import { dispatchSendKeyRequestAction } from './sendkeyrequest'
import { dispatchSignOutAtDevice } from './signoutatdevice'
@@ -67,6 +69,8 @@ export const dispatchAppLogicAction = async ({ action, deviceId, cache, eventHan
await dispatchForceSyncAction({ deviceId, action, cache })
} else if (action instanceof MarkTaskPendingAction) {
await dispatchMarkTaskPendingAction({ deviceId, action, cache })
} else if (action instanceof PingAction) {
await dispatchPingAction({ deviceId, action, cache })
} else if (action instanceof ReplyToKeyRequestAction) {
await dispatchReplyToKeyRequestAction({ deviceId, action, cache, eventHandler })
} else if (action instanceof RemoveInstalledAppsAction) {
@@ -0,0 +1,73 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2026 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 <https://www.gnu.org/licenses/>.
*/
import { PingAction } from '../../../../action'
import { types as pingTypes } from '../../../../database/ping'
import { Cache } from '../cache'
export async function dispatchPingAction ({ action, cache, deviceId }: {
deviceId: string
action: PingAction
cache: Cache
}) {
// handle insertion
if (action.event === 'ping' || action.event === 'pong') {
let type
if (action.event === 'ping') type = pingTypes.ping
else if (action.event === 'pong') type = pingTypes.pong
else throw new Error()
// delete any previous ping/pong
await cache.database.ping.destroy({
where: {
familyId: cache.familyId,
receiverDeviceId: action.deviceId,
senderDeviceId: deviceId,
type: type
},
transaction: cache.transaction
})
// insert
await cache.database.ping.create({
familyId: cache.familyId,
receiverDeviceId: action.deviceId,
senderDeviceId: deviceId,
type,
token: action.token
}, {
transaction: cache.transaction
})
// notify
cache.incrementTargetedTriggeredSyncLevel(action.deviceId, 2)
}
// handle deleting
if (action.event === 'pong' || action.event === 'clear') {
await cache.database.ping.destroy({
where: {
familyId: cache.familyId,
receiverDeviceId: deviceId,
senderDeviceId: action.deviceId,
token: action.token
},
transaction: cache.transaction
})
}
}
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann
* Copyright (C) 2019 - 2026 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,8 @@ export const dispatchChildChangePassword = async ({ action, childUserId, cache }
{
const clear = cache.getSecondPasswordHashOfChild.cache.clear
clear && clear()
if (clear) clear()
}
cache.invalidiateUserList = true
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann
* Copyright (C) 2019 - 2026 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,7 +55,8 @@ export async function dispatchChangeParentPassword ({ action, cache }: {
{
const clear = cache.getSecondPasswordHashOfParent.cache.clear
clear && clear()
if (clear) clear()
}
cache.invalidiateUserList = true
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann
* Copyright (C) 2019 - 2026 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,7 +47,8 @@ export async function dispatchSetChildPassword ({ action, cache }: {
{
const clear = cache.getSecondPasswordHashOfChild.cache.clear
clear && clear()
if (clear) clear()
}
cache.invalidiateUserList = true
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2024 Jonas Lochmann
* Copyright (C) 2019 - 2026 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
@@ -30,6 +30,7 @@ import { getDeviceDetailList } from './device-detail'
import { getDeviceList } from './device-list'
import { getDeviceDhKeys } from './dh-keys'
import { getFamilyEntry } from './family-entry'
import { getPings } from './pings'
import { getUserList } from './user-list'
import { getKeyRequests } from './key-requests'
import { getKeyResponses } from './key-responses'
@@ -52,13 +53,14 @@ export const generateServerDataStatus = async ({
const doesClientSupportCryptoApps = clientLevel >= 4
const doesClientSupportDh = clientLevel >= 5
const doesClientSupportU2f = clientLevel >= 6
const doesClientSupportPing = clientLevel >= 7
const result: ServerDataStatus = {
fullVersion: config.alwaysPro ? 1 : (
familyEntry.hasFullVersion ? parseInt(familyEntry.fullVersionUntil, 10) : 0
),
message: await getStatusMessage({ database, transaction }) || undefined,
apiLevel: 8
apiLevel: 9
}
if (familyEntry.deviceListVersion !== clientStatus.devices) {
@@ -160,5 +162,14 @@ export const generateServerDataStatus = async ({
}) || undefined
}
if (doesClientSupportPing) {
result.pings = await getPings({
database,
transaction,
familyEntry,
deviceId
})
}
return result
}
@@ -0,0 +1,52 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2026 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 <https://www.gnu.org/licenses/>.
*/
import * as Sequelize from 'sequelize'
import { Database } from '../../../database'
import { types as pingTypes } from '../../../database/ping'
import { ServerPing } from '../../../object/serverdatastatus'
import { FamilyEntry } from './family-entry'
export async function getPings ({
database, transaction, familyEntry, deviceId
}: {
database: Database
transaction: Sequelize.Transaction
familyEntry: FamilyEntry
deviceId: string
}): Promise<Array<ServerPing>> {
const savedData = await database.ping.findAll({
where: {
familyId: familyEntry.familyId,
receiverDeviceId: deviceId,
},
attributes: ['senderDeviceId', 'type', 'token'],
transaction
})
return savedData.map((row) => ({
deviceId: row.senderDeviceId,
type: convertType(row.type),
token: row.token
}))
}
function convertType(type: number): 'ping' | 'pong' {
if (type === pingTypes.ping) return 'ping'
else if (type === pingTypes.pong) return 'pong'
else throw new Error()
}
+8 -1
View File
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann
* Copyright (C) 2019 - 2026 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
@@ -34,6 +34,7 @@ export interface ServerDataStatus {
users?: ServerUserList // newUserList
krq?: Array<ServerKeyRequest> // pendingKeyRequests
kr?: Array<ServerKeyResponse> // keyResponses
pings?: Array<ServerPing>
dh?: ServerDhKey // Diffie Hellman
u2f?: U2fData
fullVersion: number // fullVersionUntil
@@ -257,6 +258,12 @@ export interface ServerKeyResponse {
signature: string
}
export interface ServerPing {
deviceId: string
token: string
type: 'ping' | 'pong'
}
export interface ServerDhKey {
v: string // version
k: string // key, base64
+2 -2
View File
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann
* Copyright (C) 2019 - 2026 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 createWebsocketHandler = ({ connectedDevicesManager, database }: {
const importantSyncForAllListener = () => {
setTimeout(() => {
socket.connected && socket.emit('should sync', { isImportant: true })
if (socket.connected) socket.emit('should sync', { isImportant: true })
}, Math.random() * 1000 * 60 /* wait up to one minute */)
}