mirror of
https://codeberg.org/timelimit/timelimit-server.git
synced 2026-08-31 19:03:45 +02:00
Add identity tokens
This commit is contained in:
+41
-7
@@ -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
|
||||
@@ -27,12 +27,13 @@ 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 { createIdentityToken, MissingSignSecretException } from '../util/identity-token'
|
||||
import { WebsocketApi } from '../websocket'
|
||||
import {
|
||||
isCreateFamilyByMailTokenRequest,
|
||||
isCreateRegisterDeviceTokenRequest, isLinkParentMailAddressRequest,
|
||||
isMailAuthTokenRequestBody, isRecoverParentPasswordRequest,
|
||||
isRemoveDeviceRequest, isSignIntoFamilyRequest
|
||||
isRemoveDeviceRequest, isSignIntoFamilyRequest, isRequestIdentityTokenRequest
|
||||
} from './validator'
|
||||
|
||||
export const createParentRouter = ({ database, websocket }: {database: Database, websocket: WebsocketApi}) => {
|
||||
@@ -131,7 +132,7 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
|
||||
}
|
||||
})
|
||||
|
||||
async function assertAuthValidAndReturnDeviceEntry ({ deviceAuthToken, parentId, secondPasswordHash, transaction }: {
|
||||
async function assertAuthValidAndReturnDetails ({ deviceAuthToken, parentId, secondPasswordHash, transaction }: {
|
||||
deviceAuthToken: string
|
||||
parentId: string
|
||||
secondPasswordHash: string
|
||||
@@ -165,6 +166,8 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
|
||||
if (!parentEntry) {
|
||||
throw new Unauthorized()
|
||||
}
|
||||
|
||||
return { deviceEntry, parentEntry }
|
||||
} else {
|
||||
const parentEntry = await database.user.findOne({
|
||||
where: {
|
||||
@@ -179,9 +182,9 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
|
||||
if (!parentEntry) {
|
||||
throw new Unauthorized()
|
||||
}
|
||||
}
|
||||
|
||||
return deviceEntry
|
||||
return { deviceEntry, parentEntry }
|
||||
}
|
||||
}
|
||||
|
||||
router.post('/create-add-device-token', json(), async (req, res, next) => {
|
||||
@@ -191,7 +194,7 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
|
||||
}
|
||||
|
||||
const { token, deviceId } = await database.transaction(async (transaction) => {
|
||||
const deviceEntry = await assertAuthValidAndReturnDeviceEntry({
|
||||
const { deviceEntry } = await assertAuthValidAndReturnDetails({
|
||||
deviceAuthToken: req.body.deviceAuthToken,
|
||||
parentId: req.body.parentId,
|
||||
secondPasswordHash: req.body.parentPasswordSecondHash,
|
||||
@@ -235,7 +238,7 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
|
||||
}
|
||||
|
||||
await database.transaction(async (transaction) => {
|
||||
const deviceEntry = await assertAuthValidAndReturnDeviceEntry({
|
||||
const { deviceEntry } = await assertAuthValidAndReturnDetails({
|
||||
deviceAuthToken: req.body.deviceAuthToken,
|
||||
parentId: req.body.parentUserId,
|
||||
secondPasswordHash: req.body.parentPasswordSecondHash,
|
||||
@@ -257,5 +260,36 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
|
||||
}
|
||||
})
|
||||
|
||||
router.post('/create-identity-token', json(), async (req, res, next) => {
|
||||
try {
|
||||
if (!isRequestIdentityTokenRequest(req.body)) {
|
||||
throw new BadRequest()
|
||||
}
|
||||
|
||||
const body = req.body
|
||||
|
||||
await database.transaction(async (transaction) => {
|
||||
const { deviceEntry, parentEntry } = await assertAuthValidAndReturnDetails({
|
||||
deviceAuthToken: body.deviceAuthToken,
|
||||
parentId: body.parentUserId,
|
||||
secondPasswordHash: body.parentPasswordSecondHash,
|
||||
transaction
|
||||
})
|
||||
|
||||
const token = await createIdentityToken({
|
||||
purpose: body.purpose,
|
||||
familyId: deviceEntry.familyId,
|
||||
userId: parentEntry.userId,
|
||||
mail: parentEntry.mail
|
||||
})
|
||||
|
||||
res.json({ token })
|
||||
})
|
||||
} catch (ex) {
|
||||
if (ex instanceof MissingSignSecretException) res.sendStatus(404)
|
||||
else next(ex)
|
||||
}
|
||||
})
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
@@ -140,6 +140,13 @@ export interface RemoveDeviceRequest {
|
||||
deviceId: string
|
||||
}
|
||||
|
||||
export interface RequestIdentityTokenRequest {
|
||||
deviceAuthToken: string
|
||||
parentUserId: string
|
||||
parentPasswordSecondHash: string
|
||||
purpose: 'purchase'
|
||||
}
|
||||
|
||||
export interface RequestWithAuthToken {
|
||||
deviceAuthToken: string
|
||||
}
|
||||
|
||||
+30
-1
@@ -1,5 +1,5 @@
|
||||
// tslint:disable
|
||||
import { ClientPushChangesRequest, ClientPullChangesRequest, MailAuthTokenRequestBody, CreateFamilyByMailTokenRequest, SignIntoFamilyRequest, RecoverParentPasswordRequest, RegisterChildDeviceRequest, SerializedParentAction, SerializedAppLogicAction, SerializedChildAction, CreateRegisterDeviceTokenRequest, CanDoPurchaseRequest, FinishPurchaseByGooglePlayRequest, LinkParentMailAddressRequest, UpdatePrimaryDeviceRequest, RemoveDeviceRequest, RequestWithAuthToken, SendMailLoginCodeRequest, SignInByMailCodeRequest } from './schema'
|
||||
import { ClientPushChangesRequest, ClientPullChangesRequest, MailAuthTokenRequestBody, CreateFamilyByMailTokenRequest, SignIntoFamilyRequest, RecoverParentPasswordRequest, RegisterChildDeviceRequest, SerializedParentAction, SerializedAppLogicAction, SerializedChildAction, CreateRegisterDeviceTokenRequest, CanDoPurchaseRequest, FinishPurchaseByGooglePlayRequest, LinkParentMailAddressRequest, UpdatePrimaryDeviceRequest, RemoveDeviceRequest, RequestIdentityTokenRequest, RequestWithAuthToken, SendMailLoginCodeRequest, SignInByMailCodeRequest } from './schema'
|
||||
import Ajv from 'ajv'
|
||||
const ajv = new Ajv()
|
||||
|
||||
@@ -3253,6 +3253,35 @@ export const isRemoveDeviceRequest: (value: unknown) => value is RemoveDeviceReq
|
||||
"definitions": definitions,
|
||||
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||
})
|
||||
export const isRequestIdentityTokenRequest: (value: unknown) => value is RequestIdentityTokenRequest = ajv.compile({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"deviceAuthToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"parentUserId": {
|
||||
"type": "string"
|
||||
},
|
||||
"parentPasswordSecondHash": {
|
||||
"type": "string"
|
||||
},
|
||||
"purpose": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"purchase"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"deviceAuthToken",
|
||||
"parentPasswordSecondHash",
|
||||
"parentUserId",
|
||||
"purpose"
|
||||
],
|
||||
"definitions": definitions,
|
||||
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||
})
|
||||
export const isRequestWithAuthToken: (value: unknown) => value is RequestWithAuthToken = ajv.compile({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
Reference in New Issue
Block a user