From 613776cbf9df02d7957801841efd285aa0442c99 Mon Sep 17 00:00:00 2001 From: Jonas Lochmann Date: Mon, 19 Sep 2022 02:00:00 +0200 Subject: [PATCH] Add U2F support --- .../ClientPullChangesRequest.schema.json | 3 + docs/schema/README.md | 14 + .../schema/SerializedParentAction.schema.json | 73 +++++ docs/schema/ServerDataStatus.schema.json | 48 +++ ...nitions-clientdatastatus-properties-u2f.md | 15 + ...gesrequest-definitions-clientdatastatus.md | 19 ++ docs/schema/clientpullchangesrequest.md | 19 ++ ...parentu2fkeyaction-properties-keyhandle.md | 15 + ...parentu2fkeyaction-properties-publickey.md | 15 + ...edaddparentu2fkeyaction-properties-type.md | 23 ++ ...nitions-serializedaddparentu2fkeyaction.md | 85 ++++++ ...parentu2fkeyaction-properties-keyhandle.md | 15 + ...parentu2fkeyaction-properties-publickey.md | 15 + ...emoveparentu2fkeyaction-properties-type.md | 23 ++ ...ions-serializedremoveparentu2fkeyaction.md | 85 ++++++ ...zedreportu2floginaction-properties-type.md | 23 ++ ...initions-serializedreportu2floginaction.md | 47 +++ docs/schema/serializedparentaction.md | 286 +++++++++++++++--- ...status-definitions-u2fdata-properties-d.md | 15 + ...status-definitions-u2fdata-properties-v.md | 15 + .../serverdatastatus-definitions-u2fdata.md | 58 ++++ ...status-definitions-u2fitem-properties-a.md | 15 + ...status-definitions-u2fitem-properties-h.md | 15 + ...status-definitions-u2fitem-properties-p.md | 15 + ...status-definitions-u2fitem-properties-u.md | 15 + .../serverdatastatus-definitions-u2fitem.md | 96 ++++++ docs/schema/serverdatastatus.md | 155 ++++++++++ src/action/addu2fkey.ts | 52 ++++ src/action/index.ts | 3 + src/action/removeu2fkey.ts | 52 ++++ src/action/reportu2flogin.ts | 30 ++ src/action/serialization/parentaction.ts | 14 +- src/api/parent.ts | 52 ++++ src/api/sync.ts | 1 + src/api/validator.ts | 116 +++++++ src/database/family.ts | 17 +- src/database/main.ts | 3 + .../migrations/20220919-create-u2f-keys.ts | 70 +++++ .../20220920-add-family-u2f-version.ts | 39 +++ src/database/u2fkey.ts | 82 +++++ src/function/dh/decrypt.ts | 68 +---- src/function/dh/index.ts | 1 + src/function/dh/shared-secret.ts | 100 ++++++ src/function/parent/create-family.ts | 3 +- src/function/sync/apply-actions/cache.ts | 14 + .../dispatch-helper/parent-action.ts | 14 +- .../dispatch-parent-action/addu2fkey.ts | 56 ++++ .../dispatch-parent-action/index.ts | 21 +- .../dispatch-parent-action/removeu2fkey.ts | 47 +++ .../dispatch-parent-action/reportu2flogin.ts | 34 +++ .../sync/apply-actions/exception/auth.ts | 22 ++ .../sync/apply-actions/exception/integrity.ts | 6 +- .../sync/apply-actions/exception/limit.ts | 24 ++ src/function/sync/apply-actions/index.ts | 21 +- src/function/sync/apply-actions/integrity.ts | 116 ++++++- src/function/sync/apply-actions/types.ts | 18 ++ .../get-server-data-status/family-entry.ts | 9 +- .../sync/get-server-data-status/index.ts | 13 +- .../sync/get-server-data-status/u2f.ts | 49 +++ src/function/u2f/index.ts | 148 +++++++++ src/object/clientdatastatus.ts | 1 + src/object/serverdatastatus.ts | 13 + src/util/binary-number.ts | 32 ++ src/util/u2fsignature.ts | 52 ++++ 64 files changed, 2501 insertions(+), 134 deletions(-) create mode 100644 docs/schema/clientpullchangesrequest-definitions-clientdatastatus-properties-u2f.md create mode 100644 docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-keyhandle.md create mode 100644 docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-publickey.md create mode 100644 docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-type.md create mode 100644 docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction.md create mode 100644 docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-keyhandle.md create mode 100644 docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-publickey.md create mode 100644 docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-type.md create mode 100644 docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction.md create mode 100644 docs/schema/serializedparentaction-definitions-serializedreportu2floginaction-properties-type.md create mode 100644 docs/schema/serializedparentaction-definitions-serializedreportu2floginaction.md create mode 100644 docs/schema/serverdatastatus-definitions-u2fdata-properties-d.md create mode 100644 docs/schema/serverdatastatus-definitions-u2fdata-properties-v.md create mode 100644 docs/schema/serverdatastatus-definitions-u2fdata.md create mode 100644 docs/schema/serverdatastatus-definitions-u2fitem-properties-a.md create mode 100644 docs/schema/serverdatastatus-definitions-u2fitem-properties-h.md create mode 100644 docs/schema/serverdatastatus-definitions-u2fitem-properties-p.md create mode 100644 docs/schema/serverdatastatus-definitions-u2fitem-properties-u.md create mode 100644 docs/schema/serverdatastatus-definitions-u2fitem.md create mode 100644 src/action/addu2fkey.ts create mode 100644 src/action/removeu2fkey.ts create mode 100644 src/action/reportu2flogin.ts create mode 100644 src/database/migration/migrations/20220919-create-u2f-keys.ts create mode 100644 src/database/migration/migrations/20220920-add-family-u2f-version.ts create mode 100644 src/database/u2fkey.ts create mode 100644 src/function/dh/shared-secret.ts create mode 100644 src/function/sync/apply-actions/dispatch-parent-action/addu2fkey.ts create mode 100644 src/function/sync/apply-actions/dispatch-parent-action/removeu2fkey.ts create mode 100644 src/function/sync/apply-actions/dispatch-parent-action/reportu2flogin.ts create mode 100644 src/function/sync/apply-actions/exception/auth.ts create mode 100644 src/function/sync/apply-actions/exception/limit.ts create mode 100644 src/function/sync/apply-actions/types.ts create mode 100644 src/function/sync/get-server-data-status/u2f.ts create mode 100644 src/function/u2f/index.ts create mode 100644 src/util/binary-number.ts create mode 100644 src/util/u2fsignature.ts diff --git a/docs/schema/ClientPullChangesRequest.schema.json b/docs/schema/ClientPullChangesRequest.schema.json index 108e7f0..994dc30 100644 --- a/docs/schema/ClientPullChangesRequest.schema.json +++ b/docs/schema/ClientPullChangesRequest.schema.json @@ -52,6 +52,9 @@ }, "dh": { "type": "string" + }, + "u2f": { + "type": "string" } }, "additionalProperties": false, diff --git a/docs/schema/README.md b/docs/schema/README.md index 2ae14f4..48d230a 100644 --- a/docs/schema/README.md +++ b/docs/schema/README.md @@ -84,6 +84,8 @@ * [SerializedAddInstalledAppsAction](./serializedapplogicaction-definitions-serializedaddinstalledappsaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddInstalledAppsAction` +* [SerializedAddParentU2fKeyAction](./serializedparentaction-definitions-serializedaddparentu2fkeyaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction` + * [SerializedAddUsedTimeAction](./serializedapplogicaction-definitions-serializedaddusedtimeaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddUsedTimeAction` * [SerializedAddUsedTimeActionVersion2](./serializedapplogicaction-definitions-serializedaddusedtimeactionversion2.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedAddUsedTimeActionVersion2` @@ -128,12 +130,16 @@ * [SerializedRemoveInstalledAppsAction](./serializedapplogicaction-definitions-serializedremoveinstalledappsaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedRemoveInstalledAppsAction` +* [SerializedRemoveParentU2fKeyAction](./serializedparentaction-definitions-serializedremoveparentu2fkeyaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction` + * [SerializedRemoveUserAction](./serializedparentaction-definitions-serializedremoveuseraction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveUserAction` * [SerializedRenameChildAction](./serializedparentaction-definitions-serializedrenamechildaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedRenameChildAction` * [SerializedReplyToKeyRequestAction](./serializedapplogicaction-definitions-serializedreplytokeyrequestaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedReplyToKeyRequestAction` +* [SerializedReportU2fLoginAction](./serializedparentaction-definitions-serializedreportu2floginaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedReportU2fLoginAction` + * [SerializedReviewChildTaskAction](./serializedparentaction-definitions-serializedreviewchildtaskaction.md) – `https://timelimit.io/SerializedParentAction#/definitions/SerializedReviewChildTaskAction` * [SerializedSendKeyRequestAction](./serializedapplogicaction-definitions-serializedsendkeyrequestaction.md) – `https://timelimit.io/SerializedAppLogicAction#/definitions/SerializedSendKeyRequestAction` @@ -250,6 +256,10 @@ * [ServerUserList](./serverdatastatus-definitions-serveruserlist.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUserList` +* [U2fData](./serverdatastatus-definitions-u2fdata.md) – `https://timelimit.io/ServerDataStatus#/definitions/U2fData` + +* [U2fItem](./serverdatastatus-definitions-u2fitem.md) – `https://timelimit.io/ServerDataStatus#/definitions/U2fItem` + * [Untitled object in ClientPullChangesRequest](./clientpullchangesrequest-definitions-clientdatastatus-properties-apps.md) – `https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/apps` * [Untitled object in ClientPullChangesRequest](./clientpullchangesrequest-definitions-clientdatastatus-properties-categories.md) – `https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/categories` @@ -364,6 +374,8 @@ * [Untitled array in ServerDataStatus](./serverdatastatus-properties-kr.md) – `https://timelimit.io/ServerDataStatus#/properties/kr` +* [Untitled array in ServerDataStatus](./serverdatastatus-definitions-u2fdata-properties-d.md) – `https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/d` + * [Untitled array in ServerDataStatus](./serverdatastatus-definitions-serverdevicelist-properties-data.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerDeviceList/properties/data` * [Untitled array in ServerDataStatus](./serverdatastatus-definitions-serverinstalledappsdata-properties-apps.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerInstalledAppsData/properties/apps` @@ -386,6 +398,8 @@ * [Untitled array in ServerDataStatus](./serverdatastatus-definitions-serveruserlist-properties-data.md) – `https://timelimit.io/ServerDataStatus#/definitions/ServerUserList/properties/data` +* [Untitled array in ServerDataStatus](./serverdatastatus-definitions-u2fdata-properties-d.md) – `https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/d` + ## Version Note The schemas linked above follow the JSON Schema Spec version: `http://json-schema.org/draft-07/schema#` diff --git a/docs/schema/SerializedParentAction.schema.json b/docs/schema/SerializedParentAction.schema.json index b9c1478..9d59d4f 100644 --- a/docs/schema/SerializedParentAction.schema.json +++ b/docs/schema/SerializedParentAction.schema.json @@ -6,6 +6,9 @@ { "$ref": "#/definitions/SerializedAddCategoryNetworkIdAction" }, + { + "$ref": "#/definitions/SerializedAddParentU2fKeyAction" + }, { "$ref": "#/definitions/SerializedAddUserAction" }, @@ -33,9 +36,15 @@ { "$ref": "#/definitions/SerializedIncrementCategoryExtraTimeAction" }, + { + "$ref": "#/definitions/SerializedReportU2fLoginAction" + }, { "$ref": "#/definitions/SerializedRemoveCategoryAppsAction" }, + { + "$ref": "#/definitions/SerializedRemoveParentU2fKeyAction" + }, { "$ref": "#/definitions/SerializedRemoveUserAction" }, @@ -198,6 +207,30 @@ ], "title": "SerializedAddCategoryNetworkIdAction" }, + "SerializedAddParentU2fKeyAction": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "ADD_PARENT_U2F" + ] + }, + "keyHandle": { + "type": "string" + }, + "publicKey": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "keyHandle", + "publicKey", + "type" + ], + "title": "SerializedAddParentU2fKeyAction" + }, "SerializedAddUserAction": { "type": "object", "properties": { @@ -535,6 +568,22 @@ ], "title": "SerializedIncrementCategoryExtraTimeAction" }, + "SerializedReportU2fLoginAction": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "REPORT_U2F_LOGIN" + ] + } + }, + "additionalProperties": false, + "required": [ + "type" + ], + "title": "SerializedReportU2fLoginAction" + }, "SerializedRemoveCategoryAppsAction": { "type": "object", "properties": { @@ -562,6 +611,30 @@ ], "title": "SerializedRemoveCategoryAppsAction" }, + "SerializedRemoveParentU2fKeyAction": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "REMOVE_PARENT_U2F" + ] + }, + "keyHandle": { + "type": "string" + }, + "publicKey": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "keyHandle", + "publicKey", + "type" + ], + "title": "SerializedRemoveParentU2fKeyAction" + }, "SerializedRemoveUserAction": { "type": "object", "properties": { diff --git a/docs/schema/ServerDataStatus.schema.json b/docs/schema/ServerDataStatus.schema.json index 9166134..97a781b 100644 --- a/docs/schema/ServerDataStatus.schema.json +++ b/docs/schema/ServerDataStatus.schema.json @@ -70,6 +70,9 @@ "dh": { "$ref": "#/definitions/ServerDhKey" }, + "u2f": { + "$ref": "#/definitions/U2fData" + }, "fullVersion": { "type": "number" }, @@ -933,6 +936,51 @@ "v" ], "title": "ServerDhKey" + }, + "U2fData": { + "type": "object", + "properties": { + "v": { + "type": "string" + }, + "d": { + "type": "array", + "items": { + "$ref": "#/definitions/U2fItem" + } + } + }, + "additionalProperties": false, + "required": [ + "d", + "v" + ], + "title": "U2fData" + }, + "U2fItem": { + "type": "object", + "properties": { + "u": { + "type": "string" + }, + "a": { + "type": "number" + }, + "h": { + "type": "string" + }, + "p": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "a", + "h", + "p", + "u" + ], + "title": "U2fItem" } }, "$schema": "http://json-schema.org/draft-07/schema#", diff --git a/docs/schema/clientpullchangesrequest-definitions-clientdatastatus-properties-u2f.md b/docs/schema/clientpullchangesrequest-definitions-clientdatastatus-properties-u2f.md new file mode 100644 index 0000000..f985903 --- /dev/null +++ b/docs/schema/clientpullchangesrequest-definitions-clientdatastatus-properties-u2f.md @@ -0,0 +1,15 @@ +# Untitled string in ClientPullChangesRequest Schema + +```txt +https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/u2f +``` + + + +| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In | +| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :---------------------------------------------------------------------------------------------------- | +| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [ClientPullChangesRequest.schema.json\*](ClientPullChangesRequest.schema.json "open original schema") | + +## u2f Type + +`string` diff --git a/docs/schema/clientpullchangesrequest-definitions-clientdatastatus.md b/docs/schema/clientpullchangesrequest-definitions-clientdatastatus.md index d3bcd1c..01f7a17 100644 --- a/docs/schema/clientpullchangesrequest-definitions-clientdatastatus.md +++ b/docs/schema/clientpullchangesrequest-definitions-clientdatastatus.md @@ -27,6 +27,7 @@ https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus | [kri](#kri) | `number` | Optional | cannot be null | [ClientPullChangesRequest](clientpullchangesrequest-definitions-clientdatastatus-properties-kri.md "https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/kri") | | [kr](#kr) | `number` | Optional | cannot be null | [ClientPullChangesRequest](clientpullchangesrequest-definitions-clientdatastatus-properties-kr.md "https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/kr") | | [dh](#dh) | `string` | Optional | cannot be null | [ClientPullChangesRequest](clientpullchangesrequest-definitions-clientdatastatus-properties-dh.md "https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/dh") | +| [u2f](#u2f) | `string` | Optional | cannot be null | [ClientPullChangesRequest](clientpullchangesrequest-definitions-clientdatastatus-properties-u2f.md "https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/u2f") | ## devices @@ -189,3 +190,21 @@ https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus ### dh Type `string` + +## u2f + + + +`u2f` + +* is optional + +* Type: `string` + +* cannot be null + +* defined in: [ClientPullChangesRequest](clientpullchangesrequest-definitions-clientdatastatus-properties-u2f.md "https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/u2f") + +### u2f Type + +`string` diff --git a/docs/schema/clientpullchangesrequest.md b/docs/schema/clientpullchangesrequest.md index 17231f5..d5ed2db 100644 --- a/docs/schema/clientpullchangesrequest.md +++ b/docs/schema/clientpullchangesrequest.md @@ -78,6 +78,7 @@ Reference this group by using | [kri](#kri) | `number` | Optional | cannot be null | [ClientPullChangesRequest](clientpullchangesrequest-definitions-clientdatastatus-properties-kri.md "https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/kri") | | [kr](#kr) | `number` | Optional | cannot be null | [ClientPullChangesRequest](clientpullchangesrequest-definitions-clientdatastatus-properties-kr.md "https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/kr") | | [dh](#dh) | `string` | Optional | cannot be null | [ClientPullChangesRequest](clientpullchangesrequest-definitions-clientdatastatus-properties-dh.md "https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/dh") | +| [u2f](#u2f) | `string` | Optional | cannot be null | [ClientPullChangesRequest](clientpullchangesrequest-definitions-clientdatastatus-properties-u2f.md "https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/u2f") | ### devices @@ -241,6 +242,24 @@ Reference this group by using `string` +### u2f + + + +`u2f` + +* is optional + +* Type: `string` + +* cannot be null + +* defined in: [ClientPullChangesRequest](clientpullchangesrequest-definitions-clientdatastatus-properties-u2f.md "https://timelimit.io/ClientPullChangesRequest#/definitions/ClientDataStatus/properties/u2f") + +#### u2f Type + +`string` + ## Definitions group CategoryDataStatus Reference this group by using diff --git a/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-keyhandle.md b/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-keyhandle.md new file mode 100644 index 0000000..b69d4b3 --- /dev/null +++ b/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-keyhandle.md @@ -0,0 +1,15 @@ +# Untitled string in SerializedParentAction Schema + +```txt +https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/keyHandle +``` + + + +| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In | +| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------------------ | +| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") | + +## keyHandle Type + +`string` diff --git a/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-publickey.md b/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-publickey.md new file mode 100644 index 0000000..2e7fdaa --- /dev/null +++ b/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-publickey.md @@ -0,0 +1,15 @@ +# Untitled string in SerializedParentAction Schema + +```txt +https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/publicKey +``` + + + +| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In | +| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------------------ | +| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") | + +## publicKey Type + +`string` diff --git a/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-type.md b/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-type.md new file mode 100644 index 0000000..a779010 --- /dev/null +++ b/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-type.md @@ -0,0 +1,23 @@ +# Untitled string in SerializedParentAction Schema + +```txt +https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/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 | [SerializedParentAction.schema.json\*](SerializedParentAction.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 | +| :----------------- | :---------- | +| `"ADD_PARENT_U2F"` | | diff --git a/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction.md b/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction.md new file mode 100644 index 0000000..2d9bb8a --- /dev/null +++ b/docs/schema/serializedparentaction-definitions-serializedaddparentu2fkeyaction.md @@ -0,0 +1,85 @@ +# SerializedAddParentU2fKeyAction Schema + +```txt +https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction +``` + + + +| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In | +| :------------------ | :--------- | :------------- | :----------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------------------ | +| Can be instantiated | No | Unknown status | No | Forbidden | Forbidden | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") | + +## SerializedAddParentU2fKeyAction Type + +`object` ([SerializedAddParentU2fKeyAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction.md)) + +# SerializedAddParentU2fKeyAction Properties + +| Property | Type | Required | Nullable | Defined by | +| :---------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [type](#type) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/type") | +| [keyHandle](#keyhandle) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-keyhandle.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/keyHandle") | +| [publicKey](#publickey) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-publickey.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/publicKey") | + +## type + + + +`type` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/type") + +### type Type + +`string` + +### type Constraints + +**enum**: the value of this property must be equal to one of the following values: + +| Value | Explanation | +| :----------------- | :---------- | +| `"ADD_PARENT_U2F"` | | + +## keyHandle + + + +`keyHandle` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-keyhandle.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/keyHandle") + +### keyHandle Type + +`string` + +## publicKey + + + +`publicKey` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-publickey.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/publicKey") + +### publicKey Type + +`string` diff --git a/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-keyhandle.md b/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-keyhandle.md new file mode 100644 index 0000000..6424fcb --- /dev/null +++ b/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-keyhandle.md @@ -0,0 +1,15 @@ +# Untitled string in SerializedParentAction Schema + +```txt +https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/keyHandle +``` + + + +| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In | +| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------------------ | +| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") | + +## keyHandle Type + +`string` diff --git a/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-publickey.md b/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-publickey.md new file mode 100644 index 0000000..48f6676 --- /dev/null +++ b/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-publickey.md @@ -0,0 +1,15 @@ +# Untitled string in SerializedParentAction Schema + +```txt +https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/publicKey +``` + + + +| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In | +| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------------------ | +| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") | + +## publicKey Type + +`string` diff --git a/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-type.md b/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-type.md new file mode 100644 index 0000000..70384bb --- /dev/null +++ b/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-type.md @@ -0,0 +1,23 @@ +# Untitled string in SerializedParentAction Schema + +```txt +https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/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 | [SerializedParentAction.schema.json\*](SerializedParentAction.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 | +| :-------------------- | :---------- | +| `"REMOVE_PARENT_U2F"` | | diff --git a/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction.md b/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction.md new file mode 100644 index 0000000..dd7f158 --- /dev/null +++ b/docs/schema/serializedparentaction-definitions-serializedremoveparentu2fkeyaction.md @@ -0,0 +1,85 @@ +# SerializedRemoveParentU2fKeyAction Schema + +```txt +https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction +``` + + + +| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In | +| :------------------ | :--------- | :------------- | :----------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------------------ | +| Can be instantiated | No | Unknown status | No | Forbidden | Forbidden | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") | + +## SerializedRemoveParentU2fKeyAction Type + +`object` ([SerializedRemoveParentU2fKeyAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction.md)) + +# SerializedRemoveParentU2fKeyAction Properties + +| Property | Type | Required | Nullable | Defined by | +| :---------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [type](#type) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/type") | +| [keyHandle](#keyhandle) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-keyhandle.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/keyHandle") | +| [publicKey](#publickey) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-publickey.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/publicKey") | + +## type + + + +`type` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/type") + +### type Type + +`string` + +### type Constraints + +**enum**: the value of this property must be equal to one of the following values: + +| Value | Explanation | +| :-------------------- | :---------- | +| `"REMOVE_PARENT_U2F"` | | + +## keyHandle + + + +`keyHandle` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-keyhandle.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/keyHandle") + +### keyHandle Type + +`string` + +## publicKey + + + +`publicKey` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-publickey.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/publicKey") + +### publicKey Type + +`string` diff --git a/docs/schema/serializedparentaction-definitions-serializedreportu2floginaction-properties-type.md b/docs/schema/serializedparentaction-definitions-serializedreportu2floginaction-properties-type.md new file mode 100644 index 0000000..0419a90 --- /dev/null +++ b/docs/schema/serializedparentaction-definitions-serializedreportu2floginaction-properties-type.md @@ -0,0 +1,23 @@ +# Untitled string in SerializedParentAction Schema + +```txt +https://timelimit.io/SerializedParentAction#/definitions/SerializedReportU2fLoginAction/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 | [SerializedParentAction.schema.json\*](SerializedParentAction.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 | +| :------------------- | :---------- | +| `"REPORT_U2F_LOGIN"` | | diff --git a/docs/schema/serializedparentaction-definitions-serializedreportu2floginaction.md b/docs/schema/serializedparentaction-definitions-serializedreportu2floginaction.md new file mode 100644 index 0000000..4ac976b --- /dev/null +++ b/docs/schema/serializedparentaction-definitions-serializedreportu2floginaction.md @@ -0,0 +1,47 @@ +# SerializedReportU2fLoginAction Schema + +```txt +https://timelimit.io/SerializedParentAction#/definitions/SerializedReportU2fLoginAction +``` + + + +| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In | +| :------------------ | :--------- | :------------- | :----------- | :---------------- | :-------------------- | :------------------ | :------------------------------------------------------------------------------------------------ | +| Can be instantiated | No | Unknown status | No | Forbidden | Forbidden | none | [SerializedParentAction.schema.json\*](SerializedParentAction.schema.json "open original schema") | + +## SerializedReportU2fLoginAction Type + +`object` ([SerializedReportU2fLoginAction](serializedparentaction-definitions-serializedreportu2floginaction.md)) + +# SerializedReportU2fLoginAction Properties + +| Property | Type | Required | Nullable | Defined by | +| :------------ | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [type](#type) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedreportu2floginaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedReportU2fLoginAction/properties/type") | + +## type + + + +`type` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedreportu2floginaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedReportU2fLoginAction/properties/type") + +### type Type + +`string` + +### type Constraints + +**enum**: the value of this property must be equal to one of the following values: + +| Value | Explanation | +| :------------------- | :---------- | +| `"REPORT_U2F_LOGIN"` | | diff --git a/docs/schema/serializedparentaction.md b/docs/schema/serializedparentaction.md index 0e218f1..3f39f3a 100644 --- a/docs/schema/serializedparentaction.md +++ b/docs/schema/serializedparentaction.md @@ -20,6 +20,8 @@ any of * [SerializedAddCategoryNetworkIdAction](serializedparentaction-definitions-serializedaddcategorynetworkidaction.md "check type definition") +* [SerializedAddParentU2fKeyAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction.md "check type definition") + * [SerializedAddUserAction](serializedparentaction-definitions-serializedadduseraction.md "check type definition") * [SerializedChangeParentPasswordAction](serializedparentaction-definitions-serializedchangeparentpasswordaction.md "check type definition") @@ -38,8 +40,12 @@ any of * [SerializedIncrementCategoryExtraTimeAction](serializedparentaction-definitions-serializedincrementcategoryextratimeaction.md "check type definition") +* [SerializedReportU2fLoginAction](serializedparentaction-definitions-serializedreportu2floginaction.md "check type definition") + * [SerializedRemoveCategoryAppsAction](serializedparentaction-definitions-serializedremovecategoryappsaction.md "check type definition") +* [SerializedRemoveParentU2fKeyAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction.md "check type definition") + * [SerializedRemoveUserAction](serializedparentaction-definitions-serializedremoveuseraction.md "check type definition") * [SerializedRenameChildAction](serializedparentaction-definitions-serializedrenamechildaction.md "check type definition") @@ -283,6 +289,82 @@ Reference this group by using `string` +## Definitions group SerializedAddParentU2fKeyAction + +Reference this group by using + +```json +{"$ref":"https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction"} +``` + +| Property | Type | Required | Nullable | Defined by | +| :---------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [type](#type-2) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/type") | +| [keyHandle](#keyhandle) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-keyhandle.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/keyHandle") | +| [publicKey](#publickey) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-publickey.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/publicKey") | + +### type + + + +`type` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/type") + +#### type Type + +`string` + +#### type Constraints + +**enum**: the value of this property must be equal to one of the following values: + +| Value | Explanation | +| :----------------- | :---------- | +| `"ADD_PARENT_U2F"` | | + +### keyHandle + + + +`keyHandle` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-keyhandle.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/keyHandle") + +#### keyHandle Type + +`string` + +### publicKey + + + +`publicKey` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedaddparentu2fkeyaction-properties-publickey.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddParentU2fKeyAction/properties/publicKey") + +#### publicKey Type + +`string` + ## Definitions group SerializedAddUserAction Reference this group by using @@ -293,7 +375,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-2) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedadduseraction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddUserAction/properties/type") | +| [type](#type-3) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedadduseraction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddUserAction/properties/type") | | [name](#name) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedadduseraction-properties-name.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddUserAction/properties/name") | | [userType](#usertype) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedadduseraction-properties-usertype.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddUserAction/properties/userType") | | [userId](#userid) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedadduseraction-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedAddUserAction/properties/userId") | @@ -522,7 +604,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :------------------------------------------ | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-3) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedchangeparentpasswordaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedChangeParentPasswordAction/properties/type") | +| [type](#type-4) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedchangeparentpasswordaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedChangeParentPasswordAction/properties/type") | | [userId](#userid-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedchangeparentpasswordaction-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedChangeParentPasswordAction/properties/userId") | | [hash](#hash-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedchangeparentpasswordaction-properties-hash.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedChangeParentPasswordAction/properties/hash") | | [secondSalt](#secondsalt-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedchangeparentpasswordaction-properties-secondsalt.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedChangeParentPasswordAction/properties/secondSalt") | @@ -655,7 +737,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-4) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedcreatecategoryaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateCategoryAction/properties/type") | +| [type](#type-5) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedcreatecategoryaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateCategoryAction/properties/type") | | [childId](#childid) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedcreatecategoryaction-properties-childid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateCategoryAction/properties/childId") | | [categoryId](#categoryid-2) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedcreatecategoryaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateCategoryAction/properties/categoryId") | | [title](#title) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedcreatecategoryaction-properties-title.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateCategoryAction/properties/title") | @@ -750,7 +832,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-5) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedcreatetimelimtruleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateTimelimtRuleAction/properties/type") | +| [type](#type-6) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedcreatetimelimtruleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateTimelimtRuleAction/properties/type") | | [rule](#rule) | `object` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedtimelimitrule.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedCreateTimelimtRuleAction/properties/rule") | ### type @@ -1008,7 +1090,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-6) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeddeletecategoryaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteCategoryAction/properties/type") | +| [type](#type-7) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeddeletecategoryaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteCategoryAction/properties/type") | | [categoryId](#categoryid-4) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeddeletecategoryaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteCategoryAction/properties/categoryId") | ### type @@ -1065,7 +1147,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-7) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeddeletechildtaskaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteChildTaskAction/properties/type") | +| [type](#type-8) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeddeletechildtaskaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteChildTaskAction/properties/type") | | [taskId](#taskid) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeddeletechildtaskaction-properties-taskid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteChildTaskAction/properties/taskId") | ### type @@ -1122,7 +1204,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :------------------ | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-8) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeddeletetimelimitruleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteTimeLimitRuleAction/properties/type") | +| [type](#type-9) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeddeletetimelimitruleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteTimeLimitRuleAction/properties/type") | | [ruleId](#ruleid-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeddeletetimelimitruleaction-properties-ruleid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedDeleteTimeLimitRuleAction/properties/ruleId") | ### type @@ -1179,7 +1261,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------------------------------------------- | :-------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-9) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedignoremanipulationaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedIgnoreManipulationAction/properties/type") | +| [type](#type-10) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedignoremanipulationaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedIgnoreManipulationAction/properties/type") | | [deviceId](#deviceid) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedignoremanipulationaction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedIgnoreManipulationAction/properties/deviceId") | | [admin](#admin) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedignoremanipulationaction-properties-admin.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedIgnoreManipulationAction/properties/admin") | | [adminA](#admina) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedignoremanipulationaction-properties-admina.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedIgnoreManipulationAction/properties/adminA") | @@ -1445,7 +1527,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------------------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-10) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedincrementcategoryextratimeaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedIncrementCategoryExtraTimeAction/properties/type") | +| [type](#type-11) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedincrementcategoryextratimeaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedIncrementCategoryExtraTimeAction/properties/type") | | [categoryId](#categoryid-5) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedincrementcategoryextratimeaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedIncrementCategoryExtraTimeAction/properties/categoryId") | | [addedExtraTime](#addedextratime) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedincrementcategoryextratimeaction-properties-addedextratime.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedIncrementCategoryExtraTimeAction/properties/addedExtraTime") | | [day](#day) | `number` | Optional | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedincrementcategoryextratimeaction-properties-day.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedIncrementCategoryExtraTimeAction/properties/day") | @@ -1530,6 +1612,44 @@ Reference this group by using `number` +## Definitions group SerializedReportU2fLoginAction + +Reference this group by using + +```json +{"$ref":"https://timelimit.io/SerializedParentAction#/definitions/SerializedReportU2fLoginAction"} +``` + +| Property | Type | Required | Nullable | Defined by | +| :--------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [type](#type-12) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedreportu2floginaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedReportU2fLoginAction/properties/type") | + +### type + + + +`type` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedreportu2floginaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedReportU2fLoginAction/properties/type") + +#### type Type + +`string` + +#### type Constraints + +**enum**: the value of this property must be equal to one of the following values: + +| Value | Explanation | +| :------------------- | :---------- | +| `"REPORT_U2F_LOGIN"` | | + ## Definitions group SerializedRemoveCategoryAppsAction Reference this group by using @@ -1540,7 +1660,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :------------------------------ | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-11) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremovecategoryappsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveCategoryAppsAction/properties/type") | +| [type](#type-13) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremovecategoryappsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveCategoryAppsAction/properties/type") | | [categoryId](#categoryid-6) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremovecategoryappsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveCategoryAppsAction/properties/categoryId") | | [packageNames](#packagenames-1) | `array` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremovecategoryappsaction-properties-packagenames.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveCategoryAppsAction/properties/packageNames") | @@ -1606,6 +1726,82 @@ Reference this group by using `string[]` +## Definitions group SerializedRemoveParentU2fKeyAction + +Reference this group by using + +```json +{"$ref":"https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction"} +``` + +| Property | Type | Required | Nullable | Defined by | +| :------------------------ | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [type](#type-14) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/type") | +| [keyHandle](#keyhandle-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-keyhandle.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/keyHandle") | +| [publicKey](#publickey-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-publickey.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/publicKey") | + +### type + + + +`type` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/type") + +#### type Type + +`string` + +#### type Constraints + +**enum**: the value of this property must be equal to one of the following values: + +| Value | Explanation | +| :-------------------- | :---------- | +| `"REMOVE_PARENT_U2F"` | | + +### keyHandle + + + +`keyHandle` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-keyhandle.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/keyHandle") + +#### keyHandle Type + +`string` + +### publicKey + + + +`publicKey` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [SerializedParentAction](serializedparentaction-definitions-serializedremoveparentu2fkeyaction-properties-publickey.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveParentU2fKeyAction/properties/publicKey") + +#### publicKey Type + +`string` + ## Definitions group SerializedRemoveUserAction Reference this group by using @@ -1616,7 +1812,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-12) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremoveuseraction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveUserAction/properties/type") | +| [type](#type-15) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremoveuseraction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveUserAction/properties/type") | | [userId](#userid-2) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremoveuseraction-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveUserAction/properties/userId") | | [authentication](#authentication) | `string` | Optional | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedremoveuseraction-properties-authentication.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRemoveUserAction/properties/authentication") | @@ -1692,7 +1888,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-13) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedrenamechildaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRenameChildAction/properties/type") | +| [type](#type-16) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedrenamechildaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRenameChildAction/properties/type") | | [childId](#childid-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedrenamechildaction-properties-childid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRenameChildAction/properties/childId") | | [newName](#newname) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedrenamechildaction-properties-newname.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedRenameChildAction/properties/newName") | @@ -1768,7 +1964,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-14) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeresetcategorynetworkidsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializeResetCategoryNetworkIdsAction/properties/type") | +| [type](#type-17) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeresetcategorynetworkidsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializeResetCategoryNetworkIdsAction/properties/type") | | [categoryId](#categoryid-7) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializeresetcategorynetworkidsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializeResetCategoryNetworkIdsAction/properties/categoryId") | ### type @@ -1825,7 +2021,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :------------------ | :-------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-15) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedreviewchildtaskaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedReviewChildTaskAction/properties/type") | +| [type](#type-18) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedreviewchildtaskaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedReviewChildTaskAction/properties/type") | | [taskId](#taskid-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedreviewchildtaskaction-properties-taskid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedReviewChildTaskAction/properties/taskId") | | [ok](#ok) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedreviewchildtaskaction-properties-ok.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedReviewChildTaskAction/properties/ok") | | [time](#time-1) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedreviewchildtaskaction-properties-time.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedReviewChildTaskAction/properties/time") | @@ -1939,7 +2135,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-16) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetcategoryextratimeaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryExtraTimeAction/properties/type") | +| [type](#type-19) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetcategoryextratimeaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryExtraTimeAction/properties/type") | | [categoryId](#categoryid-8) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetcategoryextratimeaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryExtraTimeAction/properties/categoryId") | | [newExtraTime](#newextratime) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetcategoryextratimeaction-properties-newextratime.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryExtraTimeAction/properties/newExtraTime") | | [day](#day-2) | `number` | Optional | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetcategoryextratimeaction-properties-day.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryExtraTimeAction/properties/day") | @@ -2034,7 +2230,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-17) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetcategoryforunassignedappsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryForUnassignedAppsAction/properties/type") | +| [type](#type-20) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetcategoryforunassignedappsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryForUnassignedAppsAction/properties/type") | | [childId](#childid-2) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetcategoryforunassignedappsaction-properties-childid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryForUnassignedAppsAction/properties/childId") | | [categoryId](#categoryid-9) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetcategoryforunassignedappsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetCategoryForUnassignedAppsAction/properties/categoryId") | @@ -2110,7 +2306,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-18) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetchildpasswordaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetChildPasswordAction/properties/type") | +| [type](#type-21) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetchildpasswordaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetChildPasswordAction/properties/type") | | [childId](#childid-3) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetchildpasswordaction-properties-childid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetChildPasswordAction/properties/childId") | | [newPassword](#newpassword) | `object` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-encryptableparentpassword.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetChildPasswordAction/properties/newPassword") | @@ -2186,7 +2382,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------------- | :-------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-19) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetconsiderrebootmanipulationaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetConsiderRebootManipulationAction/properties/type") | +| [type](#type-22) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetconsiderrebootmanipulationaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetConsiderRebootManipulationAction/properties/type") | | [deviceId](#deviceid-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetconsiderrebootmanipulationaction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetConsiderRebootManipulationAction/properties/deviceId") | | [enable](#enable) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetconsiderrebootmanipulationaction-properties-enable.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetConsiderRebootManipulationAction/properties/enable") | @@ -2262,7 +2458,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :------------------------------ | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-20) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdevicedefaultuseraction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceDefaultUserAction/properties/type") | +| [type](#type-23) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdevicedefaultuseraction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceDefaultUserAction/properties/type") | | [deviceId](#deviceid-2) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdevicedefaultuseraction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceDefaultUserAction/properties/deviceId") | | [defaultUserId](#defaultuserid) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdevicedefaultuseraction-properties-defaultuserid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceDefaultUserAction/properties/defaultUserId") | @@ -2338,7 +2534,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-21) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdevicedefaultusertimeoutaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceDefaultUserTimeoutAction/properties/type") | +| [type](#type-24) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdevicedefaultusertimeoutaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceDefaultUserTimeoutAction/properties/type") | | [deviceId](#deviceid-3) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdevicedefaultusertimeoutaction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceDefaultUserTimeoutAction/properties/deviceId") | | [timeout](#timeout) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdevicedefaultusertimeoutaction-properties-timeout.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceDefaultUserTimeoutAction/properties/timeout") | @@ -2414,7 +2610,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-22) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdeviceuseraction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceUserAction/properties/type") | +| [type](#type-25) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdeviceuseraction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceUserAction/properties/type") | | [deviceId](#deviceid-4) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdeviceuseraction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceUserAction/properties/deviceId") | | [userId](#userid-3) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetdeviceuseraction-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetDeviceUserAction/properties/userId") | @@ -2490,7 +2686,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------------------- | :-------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-23) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetkeepsignedinaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetKeepSignedInAction/properties/type") | +| [type](#type-26) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetkeepsignedinaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetKeepSignedInAction/properties/type") | | [deviceId](#deviceid-5) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetkeepsignedinaction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetKeepSignedInAction/properties/deviceId") | | [keepSignedIn](#keepsignedin) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetkeepsignedinaction-properties-keepsignedin.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetKeepSignedInAction/properties/keepSignedIn") | @@ -2566,7 +2762,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------------------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-24) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetparentcategoryaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetParentCategoryAction/properties/type") | +| [type](#type-27) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetparentcategoryaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetParentCategoryAction/properties/type") | | [categoryId](#categoryid-10) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetparentcategoryaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetParentCategoryAction/properties/categoryId") | | [parentCategory](#parentcategory) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetparentcategoryaction-properties-parentcategory.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetParentCategoryAction/properties/parentCategory") | @@ -2642,7 +2838,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :------------------ | :-------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-25) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetrelaxprimarydeviceaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetRelaxPrimaryDeviceAction/properties/type") | +| [type](#type-28) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetrelaxprimarydeviceaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetRelaxPrimaryDeviceAction/properties/type") | | [userId](#userid-4) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetrelaxprimarydeviceaction-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetRelaxPrimaryDeviceAction/properties/userId") | | [relax](#relax) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetrelaxprimarydeviceaction-properties-relax.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetRelaxPrimaryDeviceAction/properties/relax") | @@ -2718,7 +2914,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------------- | :-------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-26) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetsenddeviceconnected-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetSendDeviceConnected/properties/type") | +| [type](#type-29) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetsenddeviceconnected-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetSendDeviceConnected/properties/type") | | [deviceId](#deviceid-6) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetsenddeviceconnected-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetSendDeviceConnected/properties/deviceId") | | [enable](#enable-1) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetsenddeviceconnected-properties-enable.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetSendDeviceConnected/properties/enable") | @@ -2794,7 +2990,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-27) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetuserdisablelimitsuntilaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetUserDisableLimitsUntilAction/properties/type") | +| [type](#type-30) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetuserdisablelimitsuntilaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetUserDisableLimitsUntilAction/properties/type") | | [childId](#childid-4) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetuserdisablelimitsuntilaction-properties-childid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetUserDisableLimitsUntilAction/properties/childId") | | [time](#time-2) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetuserdisablelimitsuntilaction-properties-time.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetUserDisableLimitsUntilAction/properties/time") | @@ -2870,7 +3066,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-28) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetusertimezoneaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetUserTimezoneAction/properties/type") | +| [type](#type-31) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetusertimezoneaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetUserTimezoneAction/properties/type") | | [userId](#userid-5) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetusertimezoneaction-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetUserTimezoneAction/properties/userId") | | [timezone](#timezone-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedsetusertimezoneaction-properties-timezone.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedSetUserTimezoneAction/properties/timezone") | @@ -2946,7 +3142,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :--------------------------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-29) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorybatterylimitaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBatteryLimitAction/properties/type") | +| [type](#type-32) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorybatterylimitaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBatteryLimitAction/properties/type") | | [categoryId](#categoryid-11) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorybatterylimitaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBatteryLimitAction/properties/categoryId") | | [chargeLimit](#chargelimit) | `number` | Optional | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorybatterylimitaction-properties-chargelimit.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBatteryLimitAction/properties/chargeLimit") | | [mobileLimit](#mobilelimit) | `number` | Optional | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorybatterylimitaction-properties-mobilelimit.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBatteryLimitAction/properties/mobileLimit") | @@ -3041,7 +3237,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :--------------------------- | :-------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-30) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryblockallnotificationsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockAllNotificationsAction/properties/type") | +| [type](#type-33) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryblockallnotificationsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockAllNotificationsAction/properties/type") | | [categoryId](#categoryid-12) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryblockallnotificationsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockAllNotificationsAction/properties/categoryId") | | [blocked](#blocked) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryblockallnotificationsaction-properties-blocked.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockAllNotificationsAction/properties/blocked") | | [blockDelay](#blockdelay) | `number` | Optional | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryblockallnotificationsaction-properties-blockdelay.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockAllNotificationsAction/properties/blockDelay") | @@ -3136,7 +3332,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :--------------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-31) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryblockedtimesaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockedTimesAction/properties/type") | +| [type](#type-34) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryblockedtimesaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockedTimesAction/properties/type") | | [categoryId](#categoryid-13) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryblockedtimesaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockedTimesAction/properties/categoryId") | | [times](#times) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryblockedtimesaction-properties-times.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryBlockedTimesAction/properties/times") | @@ -3212,7 +3408,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :--------------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-32) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatcategorydisablelimitsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdatCategoryDisableLimitsAction/properties/type") | +| [type](#type-35) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatcategorydisablelimitsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdatCategoryDisableLimitsAction/properties/type") | | [categoryId](#categoryid-14) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatcategorydisablelimitsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdatCategoryDisableLimitsAction/properties/categoryId") | | [endTime](#endtime) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatcategorydisablelimitsaction-properties-endtime.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdatCategoryDisableLimitsAction/properties/endTime") | @@ -3288,7 +3484,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :--------------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-33) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/type") | +| [type](#type-36) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/type") | | [categoryId](#categoryid-15) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/categoryId") | | [modified](#modified) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-modified.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/modified") | | [values](#values) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategoryflagsaction-properties-values.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryFlagsAction/properties/values") | @@ -3383,7 +3579,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-34) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorysortingaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategorySortingAction/properties/type") | +| [type](#type-37) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorysortingaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategorySortingAction/properties/type") | | [categoryIds](#categoryids) | `array` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorysortingaction-properties-categoryids.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategorySortingAction/properties/categoryIds") | ### type @@ -3440,7 +3636,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :--------------------------- | :-------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-35) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction/properties/type") | +| [type](#type-38) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction/properties/type") | | [categoryId](#categoryid-16) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction/properties/categoryId") | | [blocked](#blocked-1) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction-properties-blocked.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction/properties/blocked") | | [endTime](#endtime-1) | `number` | Optional | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytemporarilyblockedaction-properties-endtime.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTemporarilyBlockedAction/properties/endTime") | @@ -3535,7 +3731,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :--------------------------- | :-------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-36) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction/properties/type") | +| [type](#type-39) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction/properties/type") | | [categoryId](#categoryid-17) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction/properties/categoryId") | | [enable](#enable-2) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction-properties-enable.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction/properties/enable") | | [flags](#flags) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytimewarningsaction-properties-flags.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTimeWarningsAction/properties/flags") | @@ -3649,7 +3845,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :--------------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-37) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytitleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTitleAction/properties/type") | +| [type](#type-40) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytitleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTitleAction/properties/type") | | [categoryId](#categoryid-18) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytitleaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTitleAction/properties/categoryId") | | [newTitle](#newtitle) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatecategorytitleaction-properties-newtitle.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateCategoryTitleAction/properties/newTitle") | @@ -3725,7 +3921,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------------------------- | :-------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-38) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/type") | +| [type](#type-41) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/type") | | [isNew](#isnew) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-isnew.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/isNew") | | [taskId](#taskid-2) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-taskid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/taskId") | | [categoryId](#categoryid-19) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatechildtaskaction-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateChildTaskAction/properties/categoryId") | @@ -3858,7 +4054,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------------- | :------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-39) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatedevicenameaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateDeviceNameAction/properties/type") | +| [type](#type-42) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatedevicenameaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateDeviceNameAction/properties/type") | | [deviceId](#deviceid-7) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatedevicenameaction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateDeviceNameAction/properties/deviceId") | | [name](#name-1) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatedevicenameaction-properties-name.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateDeviceNameAction/properties/name") | @@ -3934,7 +4130,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------------- | :-------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-40) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateenableactivitylevelblockingaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateEnableActivityLevelBlockingAction/properties/type") | +| [type](#type-43) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateenableactivitylevelblockingaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateEnableActivityLevelBlockingAction/properties/type") | | [deviceId](#deviceid-8) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateenableactivitylevelblockingaction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateEnableActivityLevelBlockingAction/properties/deviceId") | | [enable](#enable-3) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateenableactivitylevelblockingaction-properties-enable.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateEnableActivityLevelBlockingAction/properties/enable") | @@ -4010,7 +4206,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-41) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serialiizedupdatenetworktimeverificationaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerialiizedUpdateNetworkTimeVerificationAction/properties/type") | +| [type](#type-44) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serialiizedupdatenetworktimeverificationaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerialiizedUpdateNetworkTimeVerificationAction/properties/type") | | [deviceId](#deviceid-9) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serialiizedupdatenetworktimeverificationaction-properties-deviceid.md "https://timelimit.io/SerializedParentAction#/definitions/SerialiizedUpdateNetworkTimeVerificationAction/properties/deviceId") | | [mode](#mode) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serialiizedupdatenetworktimeverificationaction-properties-mode.md "https://timelimit.io/SerializedParentAction#/definitions/SerialiizedUpdateNetworkTimeVerificationAction/properties/mode") | @@ -4096,7 +4292,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :-------------------- | :-------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-42) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateparentnotificationflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateParentNotificationFlagsAction/properties/type") | +| [type](#type-45) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateparentnotificationflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateParentNotificationFlagsAction/properties/type") | | [parentId](#parentid) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateparentnotificationflagsaction-properties-parentid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateParentNotificationFlagsAction/properties/parentId") | | [flags](#flags-1) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateparentnotificationflagsaction-properties-flags.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateParentNotificationFlagsAction/properties/flags") | | [set](#set) | `boolean` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateparentnotificationflagsaction-properties-set.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateParentNotificationFlagsAction/properties/set") | @@ -4191,7 +4387,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :------------------------ | :-------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-43) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatetimelimitruleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateTimelimitRuleAction/properties/type") | +| [type](#type-46) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatetimelimitruleaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateTimelimitRuleAction/properties/type") | | [ruleId](#ruleid-2) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatetimelimitruleaction-properties-ruleid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateTimelimitRuleAction/properties/ruleId") | | [time](#time-3) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatetimelimitruleaction-properties-time.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateTimelimitRuleAction/properties/time") | | [days](#days-1) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdatetimelimitruleaction-properties-days.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateTimelimitRuleAction/properties/days") | @@ -4400,7 +4596,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :---------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-44) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/type") | +| [type](#type-47) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/type") | | [userId](#userid-6) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/userId") | | [modified](#modified-1) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-modified.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/modified") | | [values](#values-1) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserflagsaction-properties-values.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserFlagsAction/properties/values") | @@ -4495,7 +4691,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :--------------------------- | :------- | :------- | :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-45) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitlogincategory-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginCategory/properties/type") | +| [type](#type-48) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitlogincategory-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginCategory/properties/type") | | [userId](#userid-7) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitlogincategory-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginCategory/properties/userId") | | [categoryId](#categoryid-20) | `string` | Optional | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitlogincategory-properties-categoryid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginCategory/properties/categoryId") | @@ -4571,7 +4767,7 @@ Reference this group by using | Property | Type | Required | Nullable | Defined by | | :------------------------------------ | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [type](#type-46) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitloginpreblockduration-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginPreBlockDuration/properties/type") | +| [type](#type-49) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitloginpreblockduration-properties-type.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginPreBlockDuration/properties/type") | | [userId](#userid-8) | `string` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitloginpreblockduration-properties-userid.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginPreBlockDuration/properties/userId") | | [preBlockDuration](#preblockduration) | `number` | Required | cannot be null | [SerializedParentAction](serializedparentaction-definitions-serializedupdateuserlimitloginpreblockduration-properties-preblockduration.md "https://timelimit.io/SerializedParentAction#/definitions/SerializedUpdateUserLimitLoginPreBlockDuration/properties/preBlockDuration") | diff --git a/docs/schema/serverdatastatus-definitions-u2fdata-properties-d.md b/docs/schema/serverdatastatus-definitions-u2fdata-properties-d.md new file mode 100644 index 0000000..7effc2d --- /dev/null +++ b/docs/schema/serverdatastatus-definitions-u2fdata-properties-d.md @@ -0,0 +1,15 @@ +# Untitled array in ServerDataStatus Schema + +```txt +https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/d +``` + + + +| 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") | + +## d Type + +`object[]` ([U2fItem](serverdatastatus-definitions-u2fitem.md)) diff --git a/docs/schema/serverdatastatus-definitions-u2fdata-properties-v.md b/docs/schema/serverdatastatus-definitions-u2fdata-properties-v.md new file mode 100644 index 0000000..9a856e0 --- /dev/null +++ b/docs/schema/serverdatastatus-definitions-u2fdata-properties-v.md @@ -0,0 +1,15 @@ +# Untitled string in ServerDataStatus Schema + +```txt +https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/v +``` + + + +| 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") | + +## v Type + +`string` diff --git a/docs/schema/serverdatastatus-definitions-u2fdata.md b/docs/schema/serverdatastatus-definitions-u2fdata.md new file mode 100644 index 0000000..7d522ac --- /dev/null +++ b/docs/schema/serverdatastatus-definitions-u2fdata.md @@ -0,0 +1,58 @@ +# U2fData Schema + +```txt +https://timelimit.io/ServerDataStatus#/definitions/U2fData +``` + + + +| 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") | + +## U2fData Type + +`object` ([U2fData](serverdatastatus-definitions-u2fdata.md)) + +# U2fData Properties + +| Property | Type | Required | Nullable | Defined by | +| :------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | +| [v](#v) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fdata-properties-v.md "https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/v") | +| [d](#d) | `array` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fdata-properties-d.md "https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/d") | + +## v + + + +`v` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fdata-properties-v.md "https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/v") + +### v Type + +`string` + +## d + + + +`d` + +* is required + +* Type: `object[]` ([U2fItem](serverdatastatus-definitions-u2fitem.md)) + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fdata-properties-d.md "https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/d") + +### d Type + +`object[]` ([U2fItem](serverdatastatus-definitions-u2fitem.md)) diff --git a/docs/schema/serverdatastatus-definitions-u2fitem-properties-a.md b/docs/schema/serverdatastatus-definitions-u2fitem-properties-a.md new file mode 100644 index 0000000..56a41e6 --- /dev/null +++ b/docs/schema/serverdatastatus-definitions-u2fitem-properties-a.md @@ -0,0 +1,15 @@ +# Untitled number in ServerDataStatus Schema + +```txt +https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/a +``` + + + +| 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") | + +## a Type + +`number` diff --git a/docs/schema/serverdatastatus-definitions-u2fitem-properties-h.md b/docs/schema/serverdatastatus-definitions-u2fitem-properties-h.md new file mode 100644 index 0000000..309f55e --- /dev/null +++ b/docs/schema/serverdatastatus-definitions-u2fitem-properties-h.md @@ -0,0 +1,15 @@ +# Untitled string in ServerDataStatus Schema + +```txt +https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/h +``` + + + +| 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") | + +## h Type + +`string` diff --git a/docs/schema/serverdatastatus-definitions-u2fitem-properties-p.md b/docs/schema/serverdatastatus-definitions-u2fitem-properties-p.md new file mode 100644 index 0000000..b789a4c --- /dev/null +++ b/docs/schema/serverdatastatus-definitions-u2fitem-properties-p.md @@ -0,0 +1,15 @@ +# Untitled string in ServerDataStatus Schema + +```txt +https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/p +``` + + + +| 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") | + +## p Type + +`string` diff --git a/docs/schema/serverdatastatus-definitions-u2fitem-properties-u.md b/docs/schema/serverdatastatus-definitions-u2fitem-properties-u.md new file mode 100644 index 0000000..dd70975 --- /dev/null +++ b/docs/schema/serverdatastatus-definitions-u2fitem-properties-u.md @@ -0,0 +1,15 @@ +# Untitled string in ServerDataStatus Schema + +```txt +https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/u +``` + + + +| 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") | + +## u Type + +`string` diff --git a/docs/schema/serverdatastatus-definitions-u2fitem.md b/docs/schema/serverdatastatus-definitions-u2fitem.md new file mode 100644 index 0000000..0d2501f --- /dev/null +++ b/docs/schema/serverdatastatus-definitions-u2fitem.md @@ -0,0 +1,96 @@ +# U2fItem Schema + +```txt +https://timelimit.io/ServerDataStatus#/definitions/U2fItem +``` + + + +| 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") | + +## U2fItem Type + +`object` ([U2fItem](serverdatastatus-definitions-u2fitem.md)) + +# U2fItem Properties + +| Property | Type | Required | Nullable | Defined by | +| :------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | +| [u](#u) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-u.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/u") | +| [a](#a) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-a.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/a") | +| [h](#h) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-h.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/h") | +| [p](#p) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-p.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/p") | + +## u + + + +`u` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-u.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/u") + +### u Type + +`string` + +## a + + + +`a` + +* is required + +* Type: `number` + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-a.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/a") + +### a Type + +`number` + +## h + + + +`h` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-h.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/h") + +### h Type + +`string` + +## p + + + +`p` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-p.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/p") + +### p Type + +`string` diff --git a/docs/schema/serverdatastatus.md b/docs/schema/serverdatastatus.md index 4ead767..badb759 100644 --- a/docs/schema/serverdatastatus.md +++ b/docs/schema/serverdatastatus.md @@ -31,6 +31,7 @@ https://timelimit.io/ServerDataStatus | [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") | | [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") | | [message](#message) | `string` | Optional | cannot be null | [ServerDataStatus](serverdatastatus-properties-message.md "https://timelimit.io/ServerDataStatus#/properties/message") | | [apiLevel](#apilevel) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-properties-apilevel.md "https://timelimit.io/ServerDataStatus#/properties/apiLevel") | @@ -269,6 +270,24 @@ https://timelimit.io/ServerDataStatus `object` ([ServerDhKey](serverdatastatus-definitions-serverdhkey.md)) +## u2f + + + +`u2f` + +* is optional + +* Type: `object` ([U2fData](serverdatastatus-definitions-u2fdata.md)) + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fdata.md "https://timelimit.io/ServerDataStatus#/properties/u2f") + +### u2f Type + +`object` ([U2fData](serverdatastatus-definitions-u2fdata.md)) + ## fullVersion @@ -3440,3 +3459,139 @@ Reference this group by using #### k Type `string` + +## Definitions group U2fData + +Reference this group by using + +```json +{"$ref":"https://timelimit.io/ServerDataStatus#/definitions/U2fData"} +``` + +| Property | Type | Required | Nullable | Defined by | +| :-------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | +| [v](#v-1) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fdata-properties-v.md "https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/v") | +| [d](#d-2) | `array` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fdata-properties-d.md "https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/d") | + +### v + + + +`v` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fdata-properties-v.md "https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/v") + +#### v Type + +`string` + +### d + + + +`d` + +* is required + +* Type: `object[]` ([U2fItem](serverdatastatus-definitions-u2fitem.md)) + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fdata-properties-d.md "https://timelimit.io/ServerDataStatus#/definitions/U2fData/properties/d") + +#### d Type + +`object[]` ([U2fItem](serverdatastatus-definitions-u2fitem.md)) + +## Definitions group U2fItem + +Reference this group by using + +```json +{"$ref":"https://timelimit.io/ServerDataStatus#/definitions/U2fItem"} +``` + +| Property | Type | Required | Nullable | Defined by | +| :-------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | +| [u](#u) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-u.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/u") | +| [a](#a) | `number` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-a.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/a") | +| [h](#h) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-h.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/h") | +| [p](#p-2) | `string` | Required | cannot be null | [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-p.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/p") | + +### u + + + +`u` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-u.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/u") + +#### u Type + +`string` + +### a + + + +`a` + +* is required + +* Type: `number` + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-a.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/a") + +#### a Type + +`number` + +### h + + + +`h` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-h.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/h") + +#### h Type + +`string` + +### p + + + +`p` + +* is required + +* Type: `string` + +* cannot be null + +* defined in: [ServerDataStatus](serverdatastatus-definitions-u2fitem-properties-p.md "https://timelimit.io/ServerDataStatus#/definitions/U2fItem/properties/p") + +#### p Type + +`string` 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/index.ts b/src/action/index.ts index d4fcb51..d47785d 100644 --- a/src/action/index.ts +++ b/src/action/index.ts @@ -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' @@ -36,10 +37,12 @@ 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 { ReplyToKeyRequestAction } from './replytokeyrequest' +export { ReportU2fLoginAction } from './reportu2flogin' export { SetCategoryExtraTimeAction } from './setcategoryextratime' export { SetCategoryForUnassignedAppsAction } from './setcategoryforunassignedapps' export { SetChildPasswordAction } from './setchildpassword' 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/reportu2flogin.ts b/src/action/reportu2flogin.ts new file mode 100644 index 0000000..9d16f9a --- /dev/null +++ b/src/action/reportu2flogin.ts @@ -0,0 +1,30 @@ +/* + * 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' + +export class ReportU2fLoginAction extends ParentAction { + static instance = new ReportU2fLoginAction() + + private constructor () { + super() + } +} + +export interface SerializedReportU2fLoginAction { + type: 'REPORT_U2F_LOGIN' +} diff --git a/src/action/serialization/parentaction.ts b/src/action/serialization/parentaction.ts index 98b6f8c..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 - 2021 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,8 +28,10 @@ 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' @@ -68,6 +71,7 @@ import { SerializedUpdateUserLimitLoginPreBlockDuration, UpdateUserLimitLoginPre export type SerializedParentAction = SerializedAddCategoryAppsAction | SerializedAddCategoryNetworkIdAction | + SerializedAddParentU2fKeyAction | SerializedAddUserAction | SerializedChangeParentPasswordAction | SerializedCreateCategoryAction | @@ -77,7 +81,9 @@ export type SerializedParentAction = SerializedDeleteTimeLimitRuleAction | SerializedIgnoreManipulationAction | SerializedIncrementCategoryExtraTimeAction | + SerializedReportU2fLoginAction | SerializedRemoveCategoryAppsAction | + SerializedRemoveParentU2fKeyAction | SerializedRemoveUserAction | SerializedRenameChildAction | SerializeResetCategoryNetworkIdsAction | @@ -119,6 +125,8 @@ export const parseParentAction = (action: SerializedParentAction): ParentAction 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,8 +145,12 @@ 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') { diff --git a/src/api/parent.ts b/src/api/parent.ts index 050d651..8cd45c8 100644 --- a/src/api/parent.ts +++ b/src/api/parent.ts @@ -16,6 +16,7 @@ */ import { json } from 'body-parser' +import { createHmac } from 'crypto' import { Router } from 'express' import { BadRequest, Forbidden, Unauthorized } from 'http-errors' import { config } from '../config' @@ -27,6 +28,7 @@ import { getStatusByMailToken } from '../function/parent/get-status-by-mail-addr 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 { @@ -168,6 +170,56 @@ export const createParentRouter = ({ database, websocket }: {database: Database, } 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: { diff --git a/src/api/sync.ts b/src/api/sync.ts index 6fee2b5..dd95f9b 100644 --- a/src/api/sync.ts +++ b/src/api/sync.ts @@ -132,6 +132,7 @@ export const createSyncRouter = ({ database, websocket, connectedDevicesManager, 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 3ff5d5a..d26d382 100644 --- a/src/api/validator.ts +++ b/src/api/validator.ts @@ -75,6 +75,9 @@ const definitions = { }, "dh": { "type": "string" + }, + "u2f": { + "type": "string" } }, "additionalProperties": false, @@ -209,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": { @@ -535,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": { @@ -561,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": { @@ -2747,6 +2811,49 @@ const definitions = { "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" + ] } } @@ -2907,6 +3014,9 @@ export const isSerializedParentAction: (value: unknown) => value is SerializedPa { "$ref": "#/definitions/SerializedAddCategoryNetworkIdAction" }, + { + "$ref": "#/definitions/SerializedAddParentU2fKeyAction" + }, { "$ref": "#/definitions/SerializedAddUserAction" }, @@ -2934,9 +3044,15 @@ export const isSerializedParentAction: (value: unknown) => value is SerializedPa { "$ref": "#/definitions/SerializedIncrementCategoryExtraTimeAction" }, + { + "$ref": "#/definitions/SerializedReportU2fLoginAction" + }, { "$ref": "#/definitions/SerializedRemoveCategoryAppsAction" }, + { + "$ref": "#/definitions/SerializedRemoveParentU2fKeyAction" + }, { "$ref": "#/definitions/SerializedRemoveUserAction" }, diff --git a/src/database/family.ts b/src/database/family.ts index 565c221..c58aac1 100644 --- a/src/database/family.ts +++ b/src/database/family.ts @@ -33,7 +33,12 @@ export interface FamilyAttributesVersion2 { nextServerKeyRequestSeq: string } -export type FamilyAttributes = FamilyAttributesVersion1 & FamilyAttributesVersion2 +export interface FamilyAttributesVersion3 { + u2fKeysVersion: string +} + +export type FamilyAttributes = FamilyAttributesVersion1 & + FamilyAttributesVersion2 & FamilyAttributesVersion3 export type FamilyModel = Sequelize.Model & FamilyAttributes export type FamilyModelStatic = typeof Sequelize.Model & { @@ -64,9 +69,17 @@ export const attributesVersion2: SequelizeAttributes = } } +export const attributesVersion3: SequelizeAttributes = { + u2fKeysVersion: { + ...versionColumn, + defaultValue: '0000' + } +} + export const attributes: SequelizeAttributes = { ...attributesVersion1, - ...attributesVersion2 + ...attributesVersion2, + ...attributesVersion3 } export const createFamilyModel = (sequelize: Sequelize.Sequelize): FamilyModelStatic => sequelize.define('Family', attributes) as FamilyModelStatic diff --git a/src/database/main.ts b/src/database/main.ts index 379cde8..0ad7465 100644 --- a/src/database/main.ts +++ b/src/database/main.ts @@ -38,6 +38,7 @@ 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' @@ -66,6 +67,7 @@ export interface Database { purchase: PurchaseModelStatic sessionDuration: SessionDurationModelStatic timelimitRule: TimelimitRuleModelStatic + u2fKey: U2fKeyModelStatic usedTime: UsedTimeModelStatic user: UserModelStatic userLimitLoginCategory: UserLimitLoginCategoryModelStatic @@ -95,6 +97,7 @@ const createDatabase = (sequelize: Sequelize.Sequelize): Database => ({ purchase: createPurchaseModel(sequelize), sessionDuration: createSessionDurationModel(sequelize), timelimitRule: createTimelimitRuleModel(sequelize), + u2fKey: createU2fKeyModel(sequelize), usedTime: createUsedTimeModel(sequelize), user: createUserModel(sequelize), userLimitLoginCategory: createUserLimitLoginCategoryModel(sequelize), 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/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/function/dh/decrypt.ts b/src/function/dh/decrypt.ts index e664c73..bd6534c 100644 --- a/src/function/dh/decrypt.ts +++ b/src/function/dh/decrypt.ts @@ -16,10 +16,10 @@ */ import * as Sequelize from 'sequelize' -import { createDecipheriv, createPrivateKey, createPublicKey, diffieHellman } from 'crypto' +import { createDecipheriv } from 'crypto' import { Database } from '../../database' -import { calculateExpireTime } from '../../database/devicedhkey' import { isVersionId } from '../../util/token' +import { getSharedSecret, SharedSecretException } from './shared-secret' export async function decrypt({ database, transaction, familyId, deviceId, encryptedData, authData @@ -43,61 +43,24 @@ export async function decrypt({ if (!isVersionId(keyId)) throw new KeyNotFoundDecryptException('invalid key id') - const databaseKeyEntry = await database.deviceDhKey.findOne({ - where: { - familyId, - deviceId, - version: keyId - }, - transaction - }) - - if (!databaseKeyEntry) throw new KeyNotFoundDecryptException('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 KeyExpiredDecryptException() - } - - const privateKey = (() => { + const sharedSecret = await (async () => { try { - return createPrivateKey({ - key: databaseKeyEntry.privateKey, - format: 'der', - type: 'pkcs8' + return getSharedSecret({ + database, + transaction, + familyId, + deviceId, + keyId, + otherPublicKey }) } 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() + if (ex instanceof SharedSecretException) throw new SharedSecretDecryptException(ex) + throw ex } })() try { - const decipher = createDecipheriv('aes-128-gcm', sharedSecret.slice(0, 16), ivAndEncrypted.slice(0, 12), { + const decipher = createDecipheriv('aes-128-gcm', sharedSecret.sharedSecret.slice(0, 16), ivAndEncrypted.slice(0, 12), { authTagLength: 16 }) @@ -116,10 +79,7 @@ export async function decrypt({ } 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 MalformedPrivateKeyException extends DecryptException { constructor() { super('private key') } } -class MalformedPublicKeyException extends DecryptException { constructor() { super('public key') } } -class MalformedNoMatchingKeysException extends DecryptException { constructor() { super('no matching keys') } } class MalformedAuthenticationException extends DecryptException { constructor() { super('authentication data') } } -class KeyExpiredDecryptException extends DecryptException { constructor() { super('key expired') } } class KeyNotFoundDecryptException extends DecryptException { constructor(message: string) { super('key not found: ' + message) } } diff --git a/src/function/dh/index.ts b/src/function/dh/index.ts index d974161..99719da 100644 --- a/src/function/dh/index.ts +++ b/src/function/dh/index.ts @@ -18,3 +18,4 @@ export { decrypt } from './decrypt' export { generateDhKeypair } from './genkey' export { decryptParentPassword } from './parentpassword' +export { getSharedSecret, SharedSecretException } from './shared-secret' 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/create-family.ts b/src/function/parent/create-family.ts index c05676d..a84baaa 100644 --- a/src/function/parent/create-family.ts +++ b/src/function/parent/create-family.ts @@ -68,7 +68,8 @@ export const createFamily = async ({ database, mailAuthToken, firstParentDevice, // 14 days demo version fullVersionUntil: (Date.now() + 1000 * 60 * 60 * 24 * 14).toString(10), hasFullVersion: true, - nextServerKeyRequestSeq: '1' + nextServerKeyRequestSeq: '1', + u2fKeysVersion: generateIdWithinFamily() }, { transaction }) // create parent user diff --git a/src/function/sync/apply-actions/cache.ts b/src/function/sync/apply-actions/cache.ts index c184252..bf2aefd 100644 --- a/src/function/sync/apply-actions/cache.ts +++ b/src/function/sync/apply-actions/cache.ts @@ -45,6 +45,7 @@ export class Cache { invalidiateUserList = false invalidiateDeviceList = false + invalidateU2fList = false areChangesImportant = false constructor ({ familyId, deviceId, hasFullVersion, database, transaction, connectedDevicesManager }: { @@ -271,6 +272,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-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/addu2fkey.ts b/src/function/sync/apply-actions/dispatch-parent-action/addu2fkey.ts new file mode 100644 index 0000000..7ce3d42 --- /dev/null +++ b/src/function/sync/apply-actions/dispatch-parent-action/addu2fkey.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 { AddParentU2fKeyAction } from '../../../../action' +import { getU2fKeyId } from '../../../../database/u2fkey' +import { Cache } from '../cache' +import { ApplyActionUnacceptableAuthMethodException } from '../exception/auth' +import { LimitReachedException } from '../exception/limit' +import { AuthenticationMethod } from '../types' + +export async function dispatchAddU2f ({ action, cache, parentUserId, authentication }: { + action: AddParentU2fKeyAction + cache: Cache + parentUserId: string + authentication: AuthenticationMethod +}) { + if (authentication === 'u2f') { + throw new ApplyActionUnacceptableAuthMethodException() + } + + 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.areChangesImportant = true +} 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 83ac25d..b22f517 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,7 +30,9 @@ import { IncrementCategoryExtraTimeAction, ParentAction, RemoveCategoryAppsAction, + RemoveParentU2fKeyAction, RemoveUserAction, + ReportU2fLoginAction, RenameChildAction, ResetCategoryNetworkIdsAction, ReviewChildTaskAction, @@ -68,8 +71,10 @@ import { 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,7 +85,9 @@ 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 { dispatchReviewChildTaskAction } from './reviewchildtaskaction' @@ -116,12 +123,16 @@ 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 }) @@ -146,10 +157,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, authentication }) } 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) { @@ -200,6 +215,8 @@ export const dispatchParentAction = async ({ action, cache, parentUserId, source 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) { 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..1e85f96 --- /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.areChangesImportant = true +} 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/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/index.ts b/src/function/sync/apply-actions/index.ts index c857530..a425de9 100644 --- a/src/function/sync/apply-actions/index.ts +++ b/src/function/sync/apply-actions/index.ts @@ -71,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, @@ -85,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, 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/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 6e3dfd2..5d44e32 100644 --- a/src/function/sync/get-server-data-status/index.ts +++ b/src/function/sync/get-server-data-status/index.ts @@ -34,6 +34,7 @@ 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, deviceId, transaction, eventHandler @@ -51,13 +52,14 @@ export const generateServerDataStatus = async ({ 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, - apiLevel: 5 + apiLevel: 6 } if (familyEntry.deviceListVersion !== clientStatus.devices) { @@ -152,5 +154,14 @@ export const generateServerDataStatus = async ({ }) || 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/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/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/object/clientdatastatus.ts b/src/object/clientdatastatus.ts index fdc7ea3..504c6b6 100644 --- a/src/object/clientdatastatus.ts +++ b/src/object/clientdatastatus.ts @@ -25,6 +25,7 @@ export interface ClientDataStatus { 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 type ClientDataStatusApps = {[key: string]: string} // installedAppsVersionsByDeviceId diff --git a/src/object/serverdatastatus.ts b/src/object/serverdatastatus.ts index b880eeb..73584d9 100644 --- a/src/object/serverdatastatus.ts +++ b/src/object/serverdatastatus.ts @@ -35,6 +35,7 @@ export interface ServerDataStatus { krq?: Array // pendingKeyRequests kr?: Array // keyResponses dh?: ServerDhKey // Diffie Hellman + u2f?: U2fData fullVersion: number // fullVersionUntil message?: string apiLevel: number @@ -258,3 +259,15 @@ 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/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() +}