mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
only for save current code
This commit is contained in:
parent
c62169f9c3
commit
fd7d7704c2
@ -35,10 +35,13 @@ describe('test JWS creation and verification', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
jwsComA = await encode(new OpenConnectionJwtPayloadType('http://localhost:5001/api/'), keypairComA.privateKey)
|
||||
console.log('jwsComA', jwsComA)
|
||||
jwsComB = await encode(new OpenConnectionJwtPayloadType('http://localhost:5002/api/'), keypairComB.privateKey)
|
||||
console.log('jwsComB', jwsComB)
|
||||
})
|
||||
it('decode jwsComA', async () => {
|
||||
const decodedJwsComA = await decode(jwsComA)
|
||||
console.log('decodedJwsComA', decodedJwsComA)
|
||||
expect(decodedJwsComA).toEqual({
|
||||
expiration: '10m',
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
@ -47,6 +50,7 @@ describe('test JWS creation and verification', () => {
|
||||
})
|
||||
it('decode jwsComB', async () => {
|
||||
const decodedJwsComB = await decode(jwsComB)
|
||||
console.log('decodedJwsComB', decodedJwsComB)
|
||||
expect(decodedJwsComB).toEqual({
|
||||
expiration: '10m',
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
@ -55,6 +59,7 @@ describe('test JWS creation and verification', () => {
|
||||
})
|
||||
it('verify jwsComA', async () => {
|
||||
const verifiedJwsComA = await verify(jwsComA, keypairComA.publicKey)
|
||||
console.log('verifiedJwsComA', verifiedJwsComA)
|
||||
expect(verifiedJwsComA).toEqual(expect.objectContaining({
|
||||
payload: expect.objectContaining({
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
@ -64,6 +69,7 @@ describe('test JWS creation and verification', () => {
|
||||
})
|
||||
it('verify jwsComB', async () => {
|
||||
const verifiedJwsComB = await verify(jwsComB, keypairComB.publicKey)
|
||||
console.log('verifiedJwsComB', verifiedJwsComB)
|
||||
expect(verifiedJwsComB).toEqual(expect.objectContaining({
|
||||
payload: expect.objectContaining({
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
@ -79,10 +85,13 @@ describe('test JWE encryption and decryption', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
jweComA = await encrypt(new OpenConnectionJwtPayloadType('http://localhost:5001/api/'), keypairComB.publicKey)
|
||||
console.log('jweComA', jweComA)
|
||||
jweComB = await encrypt(new OpenConnectionJwtPayloadType('http://localhost:5002/api/'), keypairComA.publicKey)
|
||||
console.log('jweComB', jweComB)
|
||||
})
|
||||
it('decrypt jweComA', async () => {
|
||||
const decryptedAJwT = await decrypt(jweComA, keypairComB.privateKey)
|
||||
console.log('decryptedAJwT', decryptedAJwT)
|
||||
expect(JSON.parse(decryptedAJwT)).toEqual(expect.objectContaining({
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
url: 'http://localhost:5001/api/',
|
||||
@ -90,6 +99,7 @@ describe('test JWE encryption and decryption', () => {
|
||||
})
|
||||
it('decrypt jweComB', async () => {
|
||||
const decryptedBJwT = await decrypt(jweComB, keypairComA.privateKey)
|
||||
console.log('decryptedBJwT', decryptedBJwT)
|
||||
expect(JSON.parse(decryptedBJwT)).toEqual(expect.objectContaining({
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
url: 'http://localhost:5002/api/',
|
||||
@ -107,12 +117,18 @@ describe('test encrypted and signed JWT', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
jweComA = await encrypt(new OpenConnectionJwtPayloadType('http://localhost:5001/api/'), keypairComB.publicKey)
|
||||
console.log('jweComA', jweComA)
|
||||
jwsComA = await encode(new EncryptedJWEJwtPayloadType(jweComA), keypairComA.privateKey)
|
||||
console.log('jwsComA', jwsComA)
|
||||
jweComB = await encrypt(new OpenConnectionJwtPayloadType('http://localhost:5002/api/'), keypairComA.publicKey)
|
||||
console.log('jweComB', jweComB)
|
||||
jwsComB = await encode(new EncryptedJWEJwtPayloadType(jweComB), keypairComB.privateKey)
|
||||
console.log('jwsComB', jwsComB)
|
||||
})
|
||||
it('verify jwsComA', async () => {
|
||||
expect(await verify(jwsComA, keypairComA.publicKey)).toEqual(expect.objectContaining({
|
||||
const verifiedJwsComA = await verify(jwsComA, keypairComA.publicKey)
|
||||
console.log('verifiedJwsComA', verifiedJwsComA)
|
||||
expect(verifiedJwsComA).toEqual(expect.objectContaining({
|
||||
payload: expect.objectContaining({
|
||||
jwe: jweComA,
|
||||
tokentype: EncryptedJWEJwtPayloadType.ENCRYPTED_JWE_TYPE,
|
||||
@ -120,7 +136,9 @@ describe('test encrypted and signed JWT', () => {
|
||||
}))
|
||||
})
|
||||
it('verify jwsComB', async () => {
|
||||
expect(await verify(jwsComB, keypairComB.publicKey)).toEqual(expect.objectContaining({
|
||||
const verifiedJwsComB = await verify(jwsComB, keypairComB.publicKey)
|
||||
console.log('verifiedJwsComB', verifiedJwsComB)
|
||||
expect(verifiedJwsComB).toEqual(expect.objectContaining({
|
||||
payload: expect.objectContaining({
|
||||
jwe: jweComB,
|
||||
tokentype: EncryptedJWEJwtPayloadType.ENCRYPTED_JWE_TYPE,
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
|
||||
import { generateKeyPair, exportSPKI, exportPKCS8, KeyLike, SignJWT, decodeJwt, generalDecrypt, importPKCS8, importSPKI, jwtVerify, CompactEncrypt, compactDecrypt } from 'jose'
|
||||
import { generateKeyPair, exportSPKI, exportPKCS8, SignJWT, decodeJwt, importPKCS8, importSPKI, jwtVerify, CompactEncrypt, compactDecrypt } from 'jose'
|
||||
|
||||
import { GeneralJWE } from 'jose/dist/types/types'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
|
||||
import { JwtPayloadType } from './payloadtypes/JwtPayloadType'
|
||||
import { EncryptedJWEJwtPayloadType } from './payloadtypes/EncryptedJWEJwtPayloadType'
|
||||
|
||||
export const createKeyPair = async (): Promise<{ publicKey: string; privateKey: string }> => {
|
||||
// Generate key pair using jose library
|
||||
@ -25,17 +25,6 @@ export const verify = async (token: string, publicKey: string): Promise<JwtPaylo
|
||||
logger.info('JWT.verify... token, publicKey=', token, publicKey)
|
||||
|
||||
try {
|
||||
/*
|
||||
const { KeyObject } = await import('node:crypto')
|
||||
const cryptoKey = await crypto.subtle.importKey('raw', signkey, { name: 'RS256' }, false, [
|
||||
'sign',
|
||||
])
|
||||
const keyObject = KeyObject.from(cryptoKey)
|
||||
logger.info('JWT.verify... keyObject=', keyObject)
|
||||
logger.info('JWT.verify... keyObject.asymmetricKeyDetails=', keyObject.asymmetricKeyDetails)
|
||||
logger.info('JWT.verify... keyObject.asymmetricKeyType=', keyObject.asymmetricKeyType)
|
||||
logger.info('JWT.verify... keyObject.asymmetricKeySize=', keyObject.asymmetricKeySize)
|
||||
*/
|
||||
const importedKey = await importSPKI(publicKey, 'RS256')
|
||||
// Convert the key to JWK format if needed
|
||||
const secret = typeof importedKey === 'string'
|
||||
@ -43,8 +32,8 @@ export const verify = async (token: string, publicKey: string): Promise<JwtPaylo
|
||||
: importedKey;
|
||||
// const secret = new TextEncoder().encode(publicKey)
|
||||
const { payload } = await jwtVerify(token, secret, {
|
||||
issuer: 'urn:gradido:issuer',
|
||||
audience: 'urn:gradido:audience',
|
||||
issuer: JwtPayloadType.ISSUER,
|
||||
audience: JwtPayloadType.AUDIENCE,
|
||||
})
|
||||
logger.info('JWT.verify after jwtVerify... payload=', payload)
|
||||
return payload as JwtPayloadType
|
||||
@ -69,8 +58,8 @@ export const encode = async (payload: JwtPayloadType, privatekey: string): Promi
|
||||
alg: 'RS256',
|
||||
})
|
||||
.setIssuedAt()
|
||||
.setIssuer('urn:gradido:issuer')
|
||||
.setAudience('urn:gradido:audience')
|
||||
.setIssuer(JwtPayloadType.ISSUER)
|
||||
.setAudience(JwtPayloadType.AUDIENCE)
|
||||
.setExpirationTime(payload.expiration)
|
||||
.sign(secret)
|
||||
return token
|
||||
@ -105,26 +94,6 @@ export const encrypt = async (payload: JwtPayloadType, publicKey: string): Promi
|
||||
)
|
||||
.setProtectedHeader({ alg: 'RSA-OAEP-256', enc: 'A256GCM' })
|
||||
.encrypt(recipientKey)
|
||||
/*
|
||||
const jwe = await new EncryptJWT({ payload, 'urn:gradido:claim': true })
|
||||
.setProtectedHeader({ alg: 'RSA-OAEP-256', enc: 'A256GCM' })
|
||||
.setIssuedAt()
|
||||
.setIssuer('urn:gradido:issuer')
|
||||
.setAudience('urn:gradido:audience')
|
||||
.setExpirationTime('5m')
|
||||
.encrypt(recipientKey);
|
||||
|
||||
const token = await new EncryptJWT({ payload, 'urn:gradido:claim': true })
|
||||
.setProtectedHeader({
|
||||
alg: 'RS256',
|
||||
enc: 'A256GCM',
|
||||
})
|
||||
.setIssuedAt()
|
||||
.setIssuer('urn:gradido:issuer')
|
||||
.setAudience('urn:gradido:audience')
|
||||
.setExpirationTime(payload.expiration)
|
||||
.encrypt(encryptkey)
|
||||
*/
|
||||
logger.info('JWT.encrypt... jwe=', jwe)
|
||||
return jwe.toString()
|
||||
} catch (e) {
|
||||
@ -143,20 +112,23 @@ export const decrypt = async(jwe: string, privateKey: string): Promise<string> =
|
||||
logger.info('JWT.decrypt... plaintext=', plaintext)
|
||||
logger.info('JWT.decrypt... protectedHeader=', protectedHeader)
|
||||
return plaintext.toString()
|
||||
/*
|
||||
const generalJwe = await GeneralJWE.parse(jwe)
|
||||
const jws = await generalDecrypt(generalJwe, privateKey, { alg: 'ECDH-ES+A256KW', enc: 'A256GCM' })
|
||||
|
||||
const { payload, protectedHeader } = await jwtDecrypt(jwe, privateKey);
|
||||
|
||||
console.log(payload);
|
||||
console.log(protectedHeader);
|
||||
|
||||
logger.info('JWT.decrypt... jws=', jws)
|
||||
return jws.toString()
|
||||
*/
|
||||
} catch (e) {
|
||||
logger.error('Failed to decrypt JWT:', e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
export const encryptAndSign = async (payload: JwtPayloadType, privateKey: string, publicKey: string): Promise<string> => {
|
||||
const jwe = await encrypt(payload, publicKey)
|
||||
const jws = await encode(new EncryptedJWEJwtPayloadType(jwe), privateKey)
|
||||
return jws
|
||||
}
|
||||
|
||||
export const verifyAndDecrypt = async (token: string, privateKey: string, publicKey: string): Promise<JwtPayloadType | null> => {
|
||||
const jwePayload = await verify(token, privateKey) as EncryptedJWEJwtPayloadType
|
||||
if (!jwePayload) {
|
||||
return null
|
||||
}
|
||||
const payload = await decrypt(jwePayload.jwe as string, publicKey)
|
||||
return JSON.parse(payload) as JwtPayloadType
|
||||
}
|
||||
|
||||
@ -3,6 +3,9 @@ import { JWTPayload } from 'jose'
|
||||
import { CONFIG } from '@/config'
|
||||
|
||||
export class JwtPayloadType implements JWTPayload {
|
||||
static ISSUER = 'urn:gradido:issuer'
|
||||
static AUDIENCE = 'urn:gradido:audience'
|
||||
|
||||
iat?: number | undefined
|
||||
exp?: number | undefined
|
||||
nbf?: number | undefined
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
// import { JWTPayload } from 'jose'
|
||||
import { JwtPayloadType } from './JwtPayloadType'
|
||||
|
||||
export class OpenConnectionCallbackJwtPayloadType extends JwtPayloadType {
|
||||
static OPEN_CONNECTION_CALLBACK_TYPE = 'open-connection-callback'
|
||||
|
||||
oneTimeCode: string
|
||||
url: string
|
||||
|
||||
constructor(
|
||||
oneTimeCode: string,
|
||||
url: string,
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
super()
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
this.tokentype = OpenConnectionCallbackJwtPayloadType.OPEN_CONNECTION_CALLBACK_TYPE
|
||||
this.oneTimeCode = oneTimeCode
|
||||
this.url = url
|
||||
}
|
||||
}
|
||||
@ -7,11 +7,10 @@ import { AuthenticationClient as V1_0_AuthenticationClient } from '@/federation/
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
import { ensureUrlEndsWithSlash } from '@/util/utilities'
|
||||
|
||||
import { encryptAndSign } from '@/auth/jwt/JWT'
|
||||
import { OpenConnectionJwtPayloadType } from '@/auth/jwt/payloadtypes/OpenConnectionJwtPayloadType'
|
||||
import { OpenConnectionArgs } from './client/1_0/model/OpenConnectionArgs'
|
||||
import { AuthenticationClientFactory } from './client/AuthenticationClientFactory'
|
||||
import { OpenConnectionJwtPayloadType } from '@/auth/jwt/payloadtypes/OpenConnectionJwtPayloadType'
|
||||
import { importSPKI } from 'jose'
|
||||
import { encrypt } from '@/auth/jwt/JWT'
|
||||
|
||||
export async function startCommunityAuthentication(
|
||||
foreignFedCom: DbFederatedCommunity,
|
||||
@ -26,6 +25,7 @@ export async function startCommunityAuthentication(
|
||||
'Authentication: started with foreignFedCom:',
|
||||
foreignFedCom.endPoint,
|
||||
foreignFedCom.publicKey.toString('hex'),
|
||||
foreignCom.publicJwtKey,
|
||||
)
|
||||
// check if communityUuid is a valid v4Uuid and not still a temporary onetimecode
|
||||
if (
|
||||
@ -40,17 +40,17 @@ export async function startCommunityAuthentication(
|
||||
|
||||
if (client instanceof V1_0_AuthenticationClient) {
|
||||
if (!foreignCom.publicJwtKey) {
|
||||
throw new Error('Public JWT key not found for foreign community')
|
||||
throw new Error('Public JWT key still not exist for foreign community')
|
||||
}
|
||||
const args = new OpenConnectionArgs()
|
||||
args.publicKey = homeCom.publicKey.toString('hex')
|
||||
//create JWT with url in payload encrypted by foreignCom.publicKey and signed with homeCom.privateKey
|
||||
//create JWT with url in payload encrypted by foreignCom.publicJwtKey and signed with homeCom.privateJwtKey
|
||||
const payload = new OpenConnectionJwtPayloadType(
|
||||
ensureUrlEndsWithSlash(homeFedCom.endPoint).concat(homeFedCom.apiVersion),
|
||||
)
|
||||
const encryptKey = await importSPKI(foreignCom.publicJwtKey!, 'RS256')
|
||||
const jwt = await encrypt(payload, encryptKey)
|
||||
args.jwt = jwt
|
||||
const jws = await encryptAndSign(payload, homeCom.privateJwtKey!, foreignCom.publicJwtKey)
|
||||
// prepare the args for the client invocation
|
||||
const args = new OpenConnectionArgs()
|
||||
args.publicKey = homeCom.publicKey.toString('hex')
|
||||
args.jwt = jws
|
||||
logger.debug(
|
||||
'Authentication: before client.openConnection() args:',
|
||||
homeCom.publicKey.toString('hex'),
|
||||
|
||||
@ -14,9 +14,7 @@ import { backendLogger as logger } from '@/server/logger'
|
||||
import { startCommunityAuthentication } from './authenticateCommunities'
|
||||
import { PublicCommunityInfoLoggingView } from './client/1_0/logging/PublicCommunityInfoLogging.view'
|
||||
import { ApiVersionType } from './enum/apiVersionType'
|
||||
import { generateKeyPair, exportSPKI, exportPKCS8 } from 'jose'
|
||||
|
||||
// import { CONFIG } from '@/config/'
|
||||
import { createKeyPair } from '@/auth/jwt/JWT'
|
||||
|
||||
export async function startValidateCommunities(timerInterval: number): Promise<void> {
|
||||
if (Number.isNaN(timerInterval) || timerInterval <= 0) {
|
||||
@ -68,7 +66,11 @@ export async function validateCommunities(): Promise<void> {
|
||||
const pubComInfo = await client.getPublicCommunityInfo()
|
||||
if (pubComInfo) {
|
||||
await writeForeignCommunity(dbCom, pubComInfo)
|
||||
await startCommunityAuthentication(dbCom)
|
||||
try {
|
||||
await startCommunityAuthentication(dbCom)
|
||||
} catch (err) {
|
||||
logger.warn(`Warning: Community Authentication still not ready:`, err)
|
||||
}
|
||||
logger.debug(`Federation: write publicInfo of community: name=${pubComInfo.name}`)
|
||||
} else {
|
||||
logger.debug('Federation: missing result of getPublicCommunityInfo')
|
||||
@ -95,19 +97,13 @@ export async function writeJwtKeyPairInHomeCommunity(): Promise<DbCommunity> {
|
||||
if (homeCom) {
|
||||
if (!homeCom.publicJwtKey && !homeCom.privateJwtKey) {
|
||||
// Generate key pair using jose library
|
||||
const keyPair = await generateKeyPair('RS256');
|
||||
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity generated keypair=`, keyPair);
|
||||
const { publicKey, privateKey } = await createKeyPair();
|
||||
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity publicKey=`, publicKey);
|
||||
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity privateKey=`, privateKey);
|
||||
|
||||
// Convert keys to PEM format
|
||||
const publicKeyPem = await exportSPKI(keyPair.publicKey);
|
||||
const privateKeyPem = await exportPKCS8(keyPair.privateKey);
|
||||
|
||||
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity publicKey=`, publicKeyPem);
|
||||
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity privateKey=`, privateKeyPem);
|
||||
|
||||
homeCom.publicJwtKey = publicKeyPem;
|
||||
homeCom.publicJwtKey = publicKey;
|
||||
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity publicJwtKey.length=`, homeCom.publicJwtKey.length);
|
||||
homeCom.privateJwtKey = privateKeyPem;
|
||||
homeCom.privateJwtKey = privateKey;
|
||||
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity privateJwtKey.length=`, homeCom.privateJwtKey.length);
|
||||
await DbCommunity.save(homeCom)
|
||||
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity done`)
|
||||
|
||||
@ -6,5 +6,5 @@ export class OpenConnectionArgs {
|
||||
publicKey: string
|
||||
|
||||
@Field(() => String)
|
||||
url: string
|
||||
jwt: string
|
||||
}
|
||||
|
||||
@ -12,6 +12,9 @@ import { AuthenticationArgs } from '../model/AuthenticationArgs'
|
||||
import { OpenConnectionArgs } from '../model/OpenConnectionArgs'
|
||||
import { OpenConnectionCallbackArgs } from '../model/OpenConnectionCallbackArgs'
|
||||
import { startAuthentication, startOpenConnectionCallback } from '../util/authenticateCommunity'
|
||||
import { verifyAndDecrypt } from 'backend/src/auth/jwt/JWT'
|
||||
import { OpenConnectionJwtPayloadType } from 'backend/src/auth/jwt/payloadtypes/OpenConnectionJwtPayloadType'
|
||||
import { JwtPayloadType } from 'backend/src/auth/jwt/payloadtypes/JwtPayloadType'
|
||||
|
||||
@Resolver()
|
||||
export class AuthenticationResolver {
|
||||
@ -30,9 +33,38 @@ export class AuthenticationResolver {
|
||||
if (!comA) {
|
||||
throw new LogError(`unknown requesting community with publicKey`, pubKeyBuf.toString('hex'))
|
||||
}
|
||||
if (!comA.publicJwtKey) {
|
||||
throw new LogError(`missing publicJwtKey of community with publicKey`, pubKeyBuf.toString('hex'))
|
||||
}
|
||||
logger.debug(`Authentication: found requestedCom:`, new CommunityLoggingView(comA))
|
||||
// verify the signing of args.jwt with homeCom.privateJwtKey and decrypt args.jwt with comA.publicJwtKey
|
||||
const homeCom = await DbCommunity.findOneByOrFail({ foreign: false })
|
||||
const openConnectionJwtPayload = await verifyAndDecrypt(args.jwt, homeCom.privateJwtKey!, comA.publicJwtKey) as OpenConnectionJwtPayloadType
|
||||
if (!openConnectionJwtPayload) {
|
||||
throw new LogError(`invalid payload of community with publicKey`, pubKeyBuf.toString('hex'))
|
||||
}
|
||||
if (!openConnectionJwtPayload.url) {
|
||||
throw new LogError(`invalid url of community with publicKey`, pubKeyBuf.toString('hex'))
|
||||
}
|
||||
if (openConnectionJwtPayload.tokentype !== OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE) {
|
||||
throw new LogError(`invalid tokentype of community with publicKey`, pubKeyBuf.toString('hex'))
|
||||
}
|
||||
if (openConnectionJwtPayload.expiration < new Date().toISOString()) {
|
||||
throw new LogError(`invalid expiration of community with publicKey`, pubKeyBuf.toString('hex'))
|
||||
}
|
||||
if (openConnectionJwtPayload.issuer !== JwtPayloadType.ISSUER) {
|
||||
throw new LogError(`invalid issuer of community with publicKey`, pubKeyBuf.toString('hex'))
|
||||
}
|
||||
if (openConnectionJwtPayload.audience !== JwtPayloadType.AUDIENCE) {
|
||||
throw new LogError(`invalid audience of community with publicKey`, pubKeyBuf.toString('hex'))
|
||||
}
|
||||
const fedComA = await DbFedCommunity.findOneByOrFail({ publicKey: comA.publicKey })
|
||||
if (!openConnectionJwtPayload.url.startsWith(fedComA.endPoint)) {
|
||||
throw new LogError(`invalid url of community with publicKey`, pubKeyBuf.toString('hex'))
|
||||
}
|
||||
|
||||
// biome-ignore lint/complexity/noVoid: no await to respond immediately and invoke callback-request asynchronously
|
||||
void startOpenConnectionCallback(args, comA, CONFIG.FEDERATION_API)
|
||||
void startOpenConnectionCallback(comA, CONFIG.FEDERATION_API)
|
||||
return true
|
||||
}
|
||||
|
||||
@ -42,7 +74,7 @@ export class AuthenticationResolver {
|
||||
args: OpenConnectionCallbackArgs,
|
||||
): Promise<boolean> {
|
||||
logger.debug(`Authentication: openConnectionCallback() via apiVersion=1_0 ...`, args)
|
||||
// TODO decrypt args.url with homeCom.privateKey and verify signing with callbackFedCom.publicKey
|
||||
// TODO decrypt args.url with homeCom.privateJwtKey and verify signing with callbackFedCom.publicKey
|
||||
const endPoint = args.url.slice(0, args.url.lastIndexOf('/') + 1)
|
||||
const apiVersion = args.url.slice(args.url.lastIndexOf('/') + 1, args.url.length)
|
||||
logger.debug(`Authentication: search fedComB per:`, endPoint, apiVersion)
|
||||
|
||||
@ -13,17 +13,18 @@ import { randombytes_random } from 'sodium-native'
|
||||
|
||||
import { AuthenticationClient as V1_0_AuthenticationClient } from '@/client/1_0/AuthenticationClient'
|
||||
import { AuthenticationArgs } from '../model/AuthenticationArgs'
|
||||
import { encryptAndSign } from 'backend/src/auth/jwt/JWT'
|
||||
import { OpenConnectionCallbackJwtPayloadType } from 'backend/src/auth/jwt/payloadtypes/OpenConnectionCallbackJwtPayloadType'
|
||||
|
||||
export async function startOpenConnectionCallback(
|
||||
args: OpenConnectionArgs,
|
||||
comA: DbCommunity,
|
||||
api: string,
|
||||
): Promise<void> {
|
||||
logger.debug(`Authentication: startOpenConnectionCallback() with:`, {
|
||||
args,
|
||||
comA: new CommunityLoggingView(comA),
|
||||
})
|
||||
try {
|
||||
const homeCom = await DbCommunity.findOneByOrFail({ foreign: false })
|
||||
const homeFedCom = await DbFedCommunity.findOneByOrFail({
|
||||
foreign: false,
|
||||
apiVersion: api,
|
||||
@ -33,9 +34,9 @@ export async function startOpenConnectionCallback(
|
||||
apiVersion: api,
|
||||
publicKey: comA.publicKey,
|
||||
})
|
||||
const oneTimeCode = randombytes_random()
|
||||
const oneTimeCode = randombytes_random().toString()
|
||||
// store oneTimeCode in requestedCom.community_uuid as authenticate-request-identifier
|
||||
comA.communityUuid = oneTimeCode.toString()
|
||||
comA.communityUuid = oneTimeCode
|
||||
await DbCommunity.save(comA)
|
||||
logger.debug(
|
||||
`Authentication: stored oneTimeCode in requestedCom:`,
|
||||
@ -45,14 +46,15 @@ export async function startOpenConnectionCallback(
|
||||
const client = AuthenticationClientFactory.getInstance(fedComA)
|
||||
|
||||
if (client instanceof V1_0_AuthenticationClient) {
|
||||
const callbackArgs = new OpenConnectionCallbackArgs()
|
||||
callbackArgs.oneTimeCode = oneTimeCode.toString()
|
||||
// TODO encrypt callbackArgs.url with requestedCom.publicKey and sign it with homeCom.privateKey
|
||||
callbackArgs.url = homeFedCom.endPoint.endsWith('/')
|
||||
const url = homeFedCom.endPoint.endsWith('/')
|
||||
? homeFedCom.endPoint + homeFedCom.apiVersion
|
||||
: homeFedCom.endPoint + '/' + homeFedCom.apiVersion
|
||||
|
||||
const callbackArgs = new OpenConnectionCallbackJwtPayloadType(oneTimeCode, url)
|
||||
logger.debug(`Authentication: start openConnectionCallback with args:`, callbackArgs)
|
||||
if (await client.openConnectionCallback(callbackArgs)) {
|
||||
// encrypt callbackArgs with requestedCom.publicKey and sign it with homeCom.privateKey
|
||||
const encryptedCallbackArgs = await encryptAndSign(callbackArgs, homeCom.privateJwtKey!, comA.publicJwtKey!)
|
||||
if (await client.openConnectionCallback(encryptedCallbackArgs)) {
|
||||
logger.debug('Authentication: startOpenConnectionCallback() successful:', callbackArgs)
|
||||
} else {
|
||||
logger.error('Authentication: startOpenConnectionCallback() failed:', callbackArgs)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user