mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
use own class for buffer/string hex handling
This commit is contained in:
parent
a31ba3756a
commit
49010af54f
@ -2,15 +2,14 @@ import {
|
||||
CommunityHandshakeState as DbCommunityHandshakeState,
|
||||
CommunityHandshakeStateLoggingView,
|
||||
CommunityLoggingView,
|
||||
Community as DbCommunity,
|
||||
FederatedCommunity as DbFederatedCommunity,
|
||||
FederatedCommunityLoggingView,
|
||||
findPendingCommunityHandshake,
|
||||
getHomeCommunityWithFederatedCommunityOrFail,
|
||||
CommunityHandshakeStateType
|
||||
CommunityHandshakeStateType,
|
||||
getCommunityByPublicKeyOrFail
|
||||
} from 'database'
|
||||
import { randombytes_random } from 'sodium-native'
|
||||
import { CONFIG as CONFIG_CORE } from 'core'
|
||||
|
||||
import { AuthenticationClient as V1_0_AuthenticationClient } from '@/federation/client/1_0/AuthenticationClient'
|
||||
import { ensureUrlEndsWithSlash } from 'core'
|
||||
@ -22,6 +21,7 @@ import { AuthenticationClientFactory } from './client/AuthenticationClientFactor
|
||||
import { EncryptedTransferArgs } from 'core'
|
||||
import { CommunityHandshakeStateLogic } from 'core'
|
||||
import { CommunityLogic } from 'core'
|
||||
import { Ed25519PublicKey } from 'shared'
|
||||
|
||||
const createLogger = (functionName: string) => getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.federation.authenticateCommunities.${functionName}`)
|
||||
|
||||
@ -38,7 +38,8 @@ export async function startCommunityAuthentication(
|
||||
methodLogger.debug('homeComA', new CommunityLoggingView(homeComA))
|
||||
const homeComALogic = new CommunityLogic(homeComA)
|
||||
const homeFedComA = homeComALogic.getFederatedCommunityWithApiOrFail(fedComB.apiVersion)
|
||||
const comB = await DbCommunity.findOneByOrFail({ publicKey: fedComB.publicKey })
|
||||
const fedComBPublicKey = new Ed25519PublicKey(fedComB.publicKey)
|
||||
const comB = await getCommunityByPublicKeyOrFail(fedComBPublicKey)
|
||||
methodLogger.debug('started with comB:', new CommunityLoggingView(comB))
|
||||
// check if communityUuid is not a valid v4Uuid
|
||||
|
||||
@ -54,7 +55,7 @@ export async function startCommunityAuthentication(
|
||||
)
|
||||
|
||||
// check if a authentication is already in progress
|
||||
const existingState = await findPendingCommunityHandshake(fedComB.publicKey, fedComB.apiVersion, false)
|
||||
const existingState = await findPendingCommunityHandshake(fedComBPublicKey, fedComB.apiVersion, false)
|
||||
if (existingState) {
|
||||
const stateLogic = new CommunityHandshakeStateLogic(existingState)
|
||||
// retry on timeout or failure
|
||||
@ -72,7 +73,7 @@ export async function startCommunityAuthentication(
|
||||
throw new Error(`Public JWT key still not exist for comB ${comB.name}`)
|
||||
}
|
||||
const state = new DbCommunityHandshakeState()
|
||||
state.publicKey = fedComB.publicKey
|
||||
state.publicKey = fedComBPublicKey.asBuffer()
|
||||
state.apiVersion = fedComB.apiVersion
|
||||
state.status = CommunityHandshakeStateType.START_COMMUNITY_AUTHENTICATION
|
||||
state.handshakeId = parseInt(handshakeID)
|
||||
@ -87,7 +88,8 @@ export async function startCommunityAuthentication(
|
||||
methodLogger.debug('jws', jws)
|
||||
// prepare the args for the client invocation
|
||||
const args = new EncryptedTransferArgs()
|
||||
args.publicKey = homeComA!.publicKey.toString('hex')
|
||||
const homeComAPublicKey = new Ed25519PublicKey(homeComA!.publicKey)
|
||||
args.publicKey = homeComAPublicKey.asHex()
|
||||
args.jwt = jws
|
||||
args.handshakeID = handshakeID
|
||||
await stateSaveResolver
|
||||
|
||||
@ -12,7 +12,7 @@ import { FederationClient as V1_0_FederationClient } from '@/federation/client/1
|
||||
import { PublicCommunityInfo } from '@/federation/client/1_0/model/PublicCommunityInfo'
|
||||
import { FederationClientFactory } from '@/federation/client/FederationClientFactory'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { createKeyPair, uint32Schema } from 'shared'
|
||||
import { buffer32Schema, createKeyPair, Ed25519PublicKey, hex64Schema, uint32Schema } from 'shared'
|
||||
import { getLogger } from 'log4js'
|
||||
import { startCommunityAuthentication } from './authenticateCommunities'
|
||||
import { PublicCommunityInfoLoggingView } from './client/1_0/logging/PublicCommunityInfoLogging.view'
|
||||
@ -67,8 +67,11 @@ export async function validateCommunities(): Promise<void> {
|
||||
const client = FederationClientFactory.getInstance(dbFedComB)
|
||||
|
||||
if (client instanceof V1_0_FederationClient) {
|
||||
const pubKey = await client.getPublicKey()
|
||||
if (pubKey && pubKey === dbFedComB.publicKey.toString('hex')) {
|
||||
// throw if key isn't valid hex with length 64
|
||||
const clientPublicKey = new Ed25519PublicKey(await client.getPublicKey())
|
||||
// throw if key isn't valid hex with length 64
|
||||
const fedComBPublicKey = new Ed25519PublicKey(dbFedComB.publicKey)
|
||||
if (clientPublicKey.isSame(fedComBPublicKey)) {
|
||||
await DbFederatedCommunity.update({ id: dbFedComB.id }, { verifiedAt: new Date() })
|
||||
logger.debug(`verified dbFedComB with:`, dbFedComB.endPoint)
|
||||
const pubComInfo = await client.getPublicCommunityInfo()
|
||||
@ -84,7 +87,7 @@ export async function validateCommunities(): Promise<void> {
|
||||
logger.debug('missing result of getPublicCommunityInfo')
|
||||
}
|
||||
} else {
|
||||
logger.debug('received not matching publicKey:', pubKey, dbFedComB.publicKey.toString('hex'))
|
||||
logger.debug('received not matching publicKey:', clientPublicKey.asHex(), fedComBPublicKey.asHex())
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { FindOptionsOrder, FindOptionsWhere, IsNull, MoreThanOrEqual, Not } from 'typeorm'
|
||||
import { Community as DbCommunity } from '../entity'
|
||||
import { urlSchema, uuidv4Schema } from 'shared'
|
||||
import { Ed25519PublicKey, urlSchema, uuidv4Schema } from 'shared'
|
||||
|
||||
/**
|
||||
* Retrieves the home community, i.e., a community that is not foreign.
|
||||
@ -50,15 +50,21 @@ export async function getCommunityWithFederatedCommunityByIdentifier(
|
||||
}
|
||||
|
||||
export async function getCommunityWithFederatedCommunityWithApiOrFail(
|
||||
publicKey: Buffer,
|
||||
publicKey: Ed25519PublicKey,
|
||||
apiVersion: string
|
||||
): Promise<DbCommunity> {
|
||||
return await DbCommunity.findOneOrFail({
|
||||
where: { foreign: true, publicKey, federatedCommunities: { apiVersion } },
|
||||
where: { foreign: true, publicKey: publicKey.asBuffer(), federatedCommunities: { apiVersion } },
|
||||
relations: { federatedCommunities: true },
|
||||
})
|
||||
}
|
||||
|
||||
export async function getCommunityByPublicKeyOrFail(publicKey: Ed25519PublicKey): Promise<DbCommunity> {
|
||||
return await DbCommunity.findOneOrFail({
|
||||
where: { publicKey: publicKey.asBuffer() },
|
||||
})
|
||||
}
|
||||
|
||||
// returns all reachable communities
|
||||
// home community and all federated communities which have been verified within the last authenticationTimeoutMs
|
||||
export async function getReachableCommunities(
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Not, In } from 'typeorm'
|
||||
import { CommunityHandshakeState, CommunityHandshakeStateType} from '..'
|
||||
import { Ed25519PublicKey } from 'shared'
|
||||
|
||||
/**
|
||||
* Find a pending community handshake by public key.
|
||||
@ -8,11 +9,11 @@ import { CommunityHandshakeState, CommunityHandshakeStateType} from '..'
|
||||
* @returns The CommunityHandshakeState with associated federated community and community.
|
||||
*/
|
||||
export function findPendingCommunityHandshake(
|
||||
publicKey: Buffer, apiVersion: string, withRelations = true
|
||||
publicKey: Ed25519PublicKey, apiVersion: string, withRelations = true
|
||||
): Promise<CommunityHandshakeState | null> {
|
||||
return CommunityHandshakeState.findOne({
|
||||
where: {
|
||||
publicKey,
|
||||
publicKey: publicKey.asBuffer(),
|
||||
apiVersion,
|
||||
status: Not(In([
|
||||
CommunityHandshakeStateType.EXPIRED,
|
||||
|
||||
@ -6,17 +6,16 @@ import {
|
||||
CommunityHandshakeStateLoggingView,
|
||||
CommunityHandshakeState as DbCommunityHandshakeState,
|
||||
CommunityHandshakeStateType,
|
||||
Community as DbCommunity,
|
||||
FederatedCommunity as DbFedCommunity,
|
||||
FederatedCommunityLoggingView,
|
||||
getHomeCommunity,
|
||||
findPendingCommunityHandshake,
|
||||
findPendingCommunityHandshakeOrFailByOneTimeCode,
|
||||
} from 'database'
|
||||
import { getLogger } from 'log4js'
|
||||
import {
|
||||
AuthenticationJwtPayloadType,
|
||||
AuthenticationResponseJwtPayloadType,
|
||||
Ed25519PublicKey,
|
||||
encryptAndSign,
|
||||
OpenConnectionCallbackJwtPayloadType,
|
||||
OpenConnectionJwtPayloadType,
|
||||
@ -39,44 +38,40 @@ export class AuthenticationResolver {
|
||||
const methodLogger = createLogger('openConnection')
|
||||
methodLogger.addContext('handshakeID', args.handshakeID)
|
||||
methodLogger.debug(`openConnection() via apiVersion=1_0:`, args)
|
||||
const argsPublicKey = new Ed25519PublicKey(args.publicKey)
|
||||
try {
|
||||
const openConnectionJwtPayload = await interpretEncryptedTransferArgs(args) as OpenConnectionJwtPayloadType
|
||||
methodLogger.debug('openConnectionJwtPayload', openConnectionJwtPayload)
|
||||
if (!openConnectionJwtPayload) {
|
||||
const errmsg = `invalid OpenConnection payload of requesting community with publicKey` + args.publicKey
|
||||
methodLogger.error(errmsg)
|
||||
// no infos to the caller
|
||||
return true
|
||||
throw new Error(`invalid OpenConnection payload of requesting community with publicKey ${argsPublicKey.asHex()}`)
|
||||
}
|
||||
if (openConnectionJwtPayload.tokentype !== OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE) {
|
||||
const errmsg = `invalid tokentype of community with publicKey` + args.publicKey
|
||||
methodLogger.error(errmsg)
|
||||
// no infos to the caller
|
||||
return true
|
||||
throw new Error(`invalid tokentype of community with publicKey ${argsPublicKey.asHex()}`)
|
||||
}
|
||||
if (!openConnectionJwtPayload.url) {
|
||||
const errmsg = `invalid url of community with publicKey` + args.publicKey
|
||||
methodLogger.error(errmsg)
|
||||
// no infos to the caller
|
||||
return true
|
||||
throw new Error(`invalid url of community with publicKey ${argsPublicKey.asHex()}`)
|
||||
}
|
||||
methodLogger.debug(`vor DbFedCommunity.findOneByOrFail()...`, { publicKey: args.publicKey })
|
||||
const fedComA = await DbFedCommunity.findOneByOrFail({ publicKey: Buffer.from(args.publicKey, 'hex') })
|
||||
methodLogger.debug(`vor DbFedCommunity.findOneByOrFail()...`, { publicKey: argsPublicKey.asHex() })
|
||||
const fedComA = await DbFedCommunity.findOneByOrFail({ publicKey: argsPublicKey.asBuffer() })
|
||||
methodLogger.debug(`nach DbFedCommunity.findOneByOrFail()...`, fedComA)
|
||||
methodLogger.debug('fedComA', new FederatedCommunityLoggingView(fedComA))
|
||||
if (!openConnectionJwtPayload.url.startsWith(fedComA.endPoint)) {
|
||||
const errmsg = `invalid url of community with publicKey` + args.publicKey
|
||||
methodLogger.error(errmsg)
|
||||
// no infos to the caller
|
||||
return true
|
||||
throw new Error(`invalid url of community with publicKey ${argsPublicKey.asHex()}`)
|
||||
}
|
||||
|
||||
// no await to respond immediately and invoke callback-request asynchronously
|
||||
void startOpenConnectionCallback(args.handshakeID, args.publicKey, CONFIG.FEDERATION_API)
|
||||
void startOpenConnectionCallback(args.handshakeID, argsPublicKey, CONFIG.FEDERATION_API)
|
||||
methodLogger.debug('openConnection() successfully initiated callback and returns true immediately...')
|
||||
return true
|
||||
} catch (err) {
|
||||
methodLogger.error('invalid jwt token:', err)
|
||||
let errorText = ''
|
||||
if (err instanceof Error) {
|
||||
errorText = err.message
|
||||
} else {
|
||||
errorText = String(err)
|
||||
}
|
||||
methodLogger.error('invalid jwt token:', errorText)
|
||||
// no infos to the caller
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -93,19 +88,13 @@ export class AuthenticationResolver {
|
||||
// decrypt args.url with homeCom.privateJwtKey and verify signing with callbackFedCom.publicKey
|
||||
const openConnectionCallbackJwtPayload = await interpretEncryptedTransferArgs(args) as OpenConnectionCallbackJwtPayloadType
|
||||
if (!openConnectionCallbackJwtPayload) {
|
||||
const errmsg = `invalid OpenConnectionCallback payload of requesting community with publicKey` + args.publicKey
|
||||
methodLogger.error(errmsg)
|
||||
// no infos to the caller
|
||||
return true
|
||||
throw new Error(`invalid OpenConnectionCallback payload of requesting community with publicKey ${args.publicKey}`)
|
||||
}
|
||||
const { endPoint, apiVersion } = splitUrlInEndPointAndApiVersion(openConnectionCallbackJwtPayload.url)
|
||||
methodLogger.debug(`search fedComB per:`, endPoint, apiVersion)
|
||||
const fedComB = await DbFedCommunity.findOneBy({ endPoint, apiVersion })
|
||||
if (!fedComB) {
|
||||
const errmsg = `unknown callback community with url` + openConnectionCallbackJwtPayload.url
|
||||
methodLogger.error(errmsg)
|
||||
// no infos to the caller
|
||||
return true
|
||||
throw new Error(`unknown callback community with url ${openConnectionCallbackJwtPayload.url}`)
|
||||
}
|
||||
methodLogger.debug(
|
||||
`found fedComB and start authentication:`,
|
||||
@ -116,7 +105,14 @@ export class AuthenticationResolver {
|
||||
methodLogger.debug('openConnectionCallback() successfully initiated authentication and returns true immediately...')
|
||||
return true
|
||||
} catch (err) {
|
||||
methodLogger.error('invalid jwt token:', err)
|
||||
let errorText = ''
|
||||
if (err instanceof Error) {
|
||||
errorText = err.message
|
||||
} else {
|
||||
errorText = String(err)
|
||||
}
|
||||
methodLogger.error('invalid jwt token:', errorText)
|
||||
// no infos to the caller
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -131,22 +127,26 @@ export class AuthenticationResolver {
|
||||
methodLogger.debug(`authenticate() via apiVersion=1_0 ...`, args)
|
||||
let state: DbCommunityHandshakeState | null = null
|
||||
let stateSaveResolver: Promise<DbCommunityHandshakeState> | undefined = undefined
|
||||
const argsPublicKey = new Ed25519PublicKey(args.publicKey)
|
||||
try {
|
||||
const authArgs = await interpretEncryptedTransferArgs(args) as AuthenticationJwtPayloadType
|
||||
methodLogger.debug(`interpreted authentication payload...authArgs:`, authArgs)
|
||||
if (!authArgs) {
|
||||
throw new Error(`invalid authentication payload of requesting community with publicKey ${args.publicKey}`)
|
||||
throw new Error(`invalid authentication payload of requesting community with publicKey ${argsPublicKey.asHex()}`)
|
||||
}
|
||||
|
||||
if (!uint32Schema.safeParse(Number(authArgs.oneTimeCode)).success) {
|
||||
const validOneTimeCode = uint32Schema.safeParse(Number(authArgs.oneTimeCode))
|
||||
if (!validOneTimeCode.success) {
|
||||
throw new Error(
|
||||
`invalid oneTimeCode: ${authArgs.oneTimeCode} for community with publicKey ${authArgs.publicKey}, expect uint32`
|
||||
`invalid oneTimeCode: ${authArgs.oneTimeCode} for community with publicKey ${argsPublicKey.asHex()}, expect uint32`
|
||||
)
|
||||
}
|
||||
|
||||
state = await findPendingCommunityHandshakeOrFailByOneTimeCode(Number(authArgs.oneTimeCode))
|
||||
state = await findPendingCommunityHandshakeOrFailByOneTimeCode(validOneTimeCode.data)
|
||||
const stateLogic = new CommunityHandshakeStateLogic(state)
|
||||
if (await stateLogic.isTimeoutUpdate() || state.status !== CommunityHandshakeStateType.START_OPEN_CONNECTION_CALLBACK) {
|
||||
if (
|
||||
await stateLogic.isTimeoutUpdate() ||
|
||||
state.status !== CommunityHandshakeStateType.START_OPEN_CONNECTION_CALLBACK
|
||||
) {
|
||||
throw new Error('No valid pending community handshake found')
|
||||
}
|
||||
state.status = CommunityHandshakeStateType.SUCCESS
|
||||
@ -156,16 +156,19 @@ export class AuthenticationResolver {
|
||||
const authCom = state.federatedCommunity.community
|
||||
if (authCom) {
|
||||
methodLogger.debug('found authCom:', new CommunityLoggingView(authCom))
|
||||
methodLogger.debug('authCom.publicKey', authCom.publicKey.toString('hex'))
|
||||
methodLogger.debug('args.publicKey', args.publicKey)
|
||||
if (authCom.publicKey.compare(Buffer.from(args.publicKey, 'hex')) !== 0) {
|
||||
const authComPublicKey = new Ed25519PublicKey(authCom.publicKey)
|
||||
methodLogger.debug('authCom.publicKey', authComPublicKey.asHex())
|
||||
methodLogger.debug('args.publicKey', argsPublicKey.asHex())
|
||||
if (!authComPublicKey.isSame(argsPublicKey)) {
|
||||
throw new Error(
|
||||
`corrupt authentication call detected, oneTimeCode: ${authArgs.oneTimeCode} doesn't belong to caller: ${args.publicKey}`
|
||||
`corrupt authentication call detected, oneTimeCode: ${authArgs.oneTimeCode} doesn't belong to caller: ${argsPublicKey.asHex()}`
|
||||
)
|
||||
}
|
||||
const communityUuid = uuidv4Schema.safeParse(authArgs.uuid)
|
||||
if (!communityUuid.success) {
|
||||
throw new Error(`invalid uuid: ${authArgs.uuid} for community with publicKey ${authCom.publicKey}`)
|
||||
throw new Error(
|
||||
`invalid uuid: ${authArgs.uuid} for community with publicKey ${authComPublicKey.asHex()}`
|
||||
)
|
||||
}
|
||||
authCom.communityUuid = communityUuid.data
|
||||
authCom.authenticatedAt = new Date()
|
||||
|
||||
@ -11,7 +11,6 @@ import {
|
||||
getHomeCommunityWithFederatedCommunityOrFail,
|
||||
} from 'database'
|
||||
import { getLogger, Logger } from 'log4js'
|
||||
import { validate as validateUUID, version as versionUUID } from 'uuid'
|
||||
|
||||
import { AuthenticationClientFactory } from '@/client/AuthenticationClientFactory'
|
||||
import { randombytes_random } from 'sodium-native'
|
||||
@ -21,8 +20,10 @@ import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import {
|
||||
AuthenticationJwtPayloadType,
|
||||
AuthenticationResponseJwtPayloadType,
|
||||
Ed25519PublicKey,
|
||||
encryptAndSign,
|
||||
OpenConnectionCallbackJwtPayloadType,
|
||||
uuidv4Schema,
|
||||
verifyAndDecrypt
|
||||
} from 'shared'
|
||||
import { CommunityHandshakeState as DbCommunityHandshakeState, CommunityHandshakeStateType } from 'database'
|
||||
@ -42,7 +43,7 @@ async function errorState(
|
||||
|
||||
export async function startOpenConnectionCallback(
|
||||
handshakeID: string,
|
||||
publicKey: string,
|
||||
publicKey: Ed25519PublicKey,
|
||||
api: string,
|
||||
): Promise<void> {
|
||||
const methodLogger = createLogger('startOpenConnectionCallback')
|
||||
@ -50,8 +51,7 @@ export async function startOpenConnectionCallback(
|
||||
methodLogger.debug(`Authentication: startOpenConnectionCallback() with:`, {
|
||||
publicKey,
|
||||
})
|
||||
const publicKeyBuffer = Buffer.from(publicKey, 'hex')
|
||||
const pendingState = await findPendingCommunityHandshake(publicKeyBuffer, api, false)
|
||||
const pendingState = await findPendingCommunityHandshake(publicKey, api, false)
|
||||
if (pendingState) {
|
||||
const stateLogic = new CommunityHandshakeStateLogic(pendingState)
|
||||
// retry on timeout or failure
|
||||
@ -66,7 +66,7 @@ export async function startOpenConnectionCallback(
|
||||
try {
|
||||
const [homeComB, comA] = await Promise.all([
|
||||
getHomeCommunityWithFederatedCommunityOrFail(api),
|
||||
getCommunityWithFederatedCommunityWithApiOrFail(publicKeyBuffer, api),
|
||||
getCommunityWithFederatedCommunityWithApiOrFail(publicKey, api),
|
||||
])
|
||||
// load helpers
|
||||
const homeComBLogic = new CommunityLogic(homeComB)
|
||||
@ -79,7 +79,7 @@ export async function startOpenConnectionCallback(
|
||||
const oneTimeCode = randombytes_random()
|
||||
const oneTimeCodeString = oneTimeCode.toString()
|
||||
|
||||
state.publicKey = publicKeyBuffer
|
||||
state.publicKey = publicKey.asBuffer()
|
||||
state.apiVersion = api
|
||||
state.status = CommunityHandshakeStateType.START_OPEN_CONNECTION_CALLBACK
|
||||
state.handshakeId = parseInt(handshakeID)
|
||||
@ -100,7 +100,7 @@ export async function startOpenConnectionCallback(
|
||||
// encrypt callbackArgs with requestedCom.publicJwtKey and sign it with homeCom.privateJwtKey
|
||||
const jwt = await encryptAndSign(callbackArgs, homeComB.privateJwtKey!, comA.publicJwtKey!)
|
||||
const args = new EncryptedTransferArgs()
|
||||
args.publicKey = homeComB.publicKey.toString('hex')
|
||||
args.publicKey = new Ed25519PublicKey(homeComB.publicKey).asHex()
|
||||
args.jwt = jwt
|
||||
args.handshakeID = handshakeID
|
||||
await stateSaveResolver
|
||||
@ -140,21 +140,25 @@ export async function startAuthentication(
|
||||
})
|
||||
let state: DbCommunityHandshakeState | null = null
|
||||
let stateSaveResolver: Promise<DbCommunityHandshakeState> | undefined = undefined
|
||||
const fedComBPublicKey = new Ed25519PublicKey(fedComB.publicKey)
|
||||
try {
|
||||
const homeComA = await getHomeCommunity()
|
||||
const comB = await DbCommunity.findOneByOrFail({
|
||||
foreign: true,
|
||||
publicKey: fedComB.publicKey,
|
||||
publicKey: fedComBPublicKey.asBuffer(),
|
||||
})
|
||||
if (!comB.publicJwtKey) {
|
||||
throw new Error('Public JWT key still not exist for foreign community')
|
||||
}
|
||||
state = await findPendingCommunityHandshake(fedComB.publicKey, fedComB.apiVersion, false)
|
||||
state = await findPendingCommunityHandshake(fedComBPublicKey, fedComB.apiVersion, false)
|
||||
if (!state) {
|
||||
throw new Error('No pending community handshake found')
|
||||
}
|
||||
const stateLogic = new CommunityHandshakeStateLogic(state)
|
||||
if (await stateLogic.isTimeoutUpdate() || state.status !== CommunityHandshakeStateType.START_COMMUNITY_AUTHENTICATION) {
|
||||
if (
|
||||
await stateLogic.isTimeoutUpdate() ||
|
||||
state.status !== CommunityHandshakeStateType.START_COMMUNITY_AUTHENTICATION
|
||||
) {
|
||||
methodLogger.debug('invalid state', new CommunityHandshakeStateLoggingView(state))
|
||||
throw new Error('No valid pending community handshake found')
|
||||
}
|
||||
@ -168,7 +172,7 @@ export async function startAuthentication(
|
||||
// encrypt authenticationArgs.uuid with fedComB.publicJwtKey and sign it with homeCom.privateJwtKey
|
||||
const jwt = await encryptAndSign(authenticationArgs, homeComA!.privateJwtKey!, comB.publicJwtKey!)
|
||||
const args = new EncryptedTransferArgs()
|
||||
args.publicKey = homeComA!.publicKey.toString('hex')
|
||||
args.publicKey = new Ed25519PublicKey(homeComA!.publicKey).asHex()
|
||||
args.jwt = jwt
|
||||
args.handshakeID = handshakeID
|
||||
methodLogger.debug(`invoke authenticate() with:`, args)
|
||||
@ -183,10 +187,10 @@ export async function startAuthentication(
|
||||
new FederatedCommunityLoggingView(fedComB),
|
||||
)
|
||||
if (payload.tokentype !== AuthenticationResponseJwtPayloadType.AUTHENTICATION_RESPONSE_TYPE) {
|
||||
throw new Error(`Invalid tokentype in authenticate-response of community with publicKey ${comB.publicKey}`)
|
||||
throw new Error(`Invalid tokentype in authenticate-response of community with publicKey ${fedComBPublicKey.asHex()}`)
|
||||
}
|
||||
if (!payload.uuid || !validateUUID(payload.uuid) || versionUUID(payload.uuid) !== 4) {
|
||||
throw new Error(`Invalid uuid in authenticate-response of community with publicKey ${comB.publicKey}`)
|
||||
if (!uuidv4Schema.safeParse(payload.uuid).success) {
|
||||
throw new Error(`Invalid uuid in authenticate-response of community with publicKey ${fedComBPublicKey.asHex()}`)
|
||||
}
|
||||
comB.communityUuid = payload.uuid
|
||||
comB.authenticatedAt = new Date()
|
||||
|
||||
41
shared/src/helper/BinaryData.ts
Normal file
41
shared/src/helper/BinaryData.ts
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Class mainly for handling ed25519 public keys,
|
||||
* to make sure we have always the correct Format (Buffer or Hex String)
|
||||
*/
|
||||
export class BinaryData {
|
||||
private buf: Buffer
|
||||
private hex: string
|
||||
|
||||
constructor(input: Buffer | string | undefined) {
|
||||
if (typeof input === 'string') {
|
||||
this.buf = Buffer.from(input, 'hex')
|
||||
this.hex = input
|
||||
} else if (Buffer.isBuffer(input)) {
|
||||
this.buf = input
|
||||
this.hex = input.toString('hex')
|
||||
} else {
|
||||
throw new Error('Either valid hex string or Buffer expected')
|
||||
}
|
||||
}
|
||||
|
||||
asBuffer(): Buffer {
|
||||
return this.buf
|
||||
}
|
||||
|
||||
asHex(): string {
|
||||
return this.hex
|
||||
}
|
||||
|
||||
isSame(other: BinaryData): boolean {
|
||||
return this.buf.compare(other.buf) === 0
|
||||
}
|
||||
}
|
||||
|
||||
export class Ed25519PublicKey extends BinaryData {
|
||||
constructor(input: Buffer | string | undefined) {
|
||||
super(input)
|
||||
if (this.asBuffer().length !== 32) {
|
||||
throw new Error('Invalid ed25519 public key length')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1 +1,2 @@
|
||||
export * from './updateField'
|
||||
export * from './updateField'
|
||||
export * from './BinaryData'
|
||||
@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from 'bun:test'
|
||||
import { uuidv4Schema, uint32Schema } from './base.schema'
|
||||
import { generateKeyPairSync } from 'node:crypto'
|
||||
import { uuidv4Schema, uint32Schema, buffer32Schema } from './base.schema'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
describe('uuidv4 schema', () => {
|
||||
@ -22,3 +23,17 @@ describe('uint32 schema', () => {
|
||||
expect(uint32Schema.safeParse(2092352810).success).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
describe('buffer32 schema', () => {
|
||||
it('should validate buffer', () => {
|
||||
const { publicKey } = generateKeyPairSync('ed25519')
|
||||
const buffer = publicKey.export({ type: 'spki', format: 'der' }).slice(-32)
|
||||
expect(Buffer.isBuffer(buffer)).toBeTruthy()
|
||||
expect(buffer.length).toBe(32)
|
||||
expect(buffer32Schema.safeParse(buffer).success).toBeTruthy()
|
||||
})
|
||||
|
||||
it("shouldn't validate string", () => {
|
||||
expect(buffer32Schema.safeParse('3e1a2eecc95c48fedf47a522a8c77b91').success).toBeFalsy()
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
import { string, number } from 'zod'
|
||||
import { string, number, custom } from 'zod'
|
||||
import { validate, version } from 'uuid'
|
||||
|
||||
export const uuidv4Schema = string().refine((val: string) => validate(val) && version(val) === 4, 'Invalid uuid')
|
||||
export const emailSchema = string().email()
|
||||
export const urlSchema = string().url()
|
||||
export const uint32Schema = number().positive().lte(4294967295)
|
||||
export const uint32Schema = number().positive().lte(4294967295)
|
||||
export const buffer32Schema = custom<Buffer>(
|
||||
(val: Buffer) => Buffer.isBuffer(val) && val.length === 32,
|
||||
'Invalid buffer'
|
||||
)
|
||||
export const hex64Schema = string().length(64).regex(/^[0-9A-Fa-f]$/)
|
||||
Loading…
x
Reference in New Issue
Block a user