change to encryption on openCommunication()

This commit is contained in:
clauspeterhuebner 2025-06-17 02:27:46 +02:00
parent 582fc6c58c
commit de2566d09b
9 changed files with 85 additions and 8 deletions

View File

@ -1,6 +1,5 @@
import { createPrivateKey, sign } from 'node:crypto'
import { JWTPayload, SignJWT, decodeJwt, jwtVerify } from 'jose'
import { GeneralEncrypt, KeyLike, SignJWT, decodeJwt, jwtVerify } from 'jose'
import { LogError } from '@/server/LogError'
import { backendLogger as logger } from '@/server/logger'
@ -68,3 +67,39 @@ export const decode = (token: string): JwtPayloadType => {
const { payload } = decodeJwt(token)
return payload as JwtPayloadType
}
export const encrypt = async(payload: JwtPayloadType, encryptkey: KeyLike): Promise<string> => {
logger.info('JWT.encrypt... payload=', payload)
logger.info('JWT.encrypt... encryptkey=', encryptkey)
try {
// Convert the key to JWK format if needed
const recipientKey = typeof encryptkey === 'string'
? JSON.parse(encryptkey)
: encryptkey;
const jwe = await new GeneralEncrypt(
new TextEncoder().encode(JSON.stringify(payload)),
)
.setProtectedHeader({ enc: 'A256GCM' })
.addRecipient(recipientKey)
.setUnprotectedHeader({ alg: 'ECDH-ES+A256KW' })
.encrypt()
/*
const token = await new EncryptJWT({ payload, 'urn:gradido:claim': true })
.setProtectedHeader({
alg: 'HS256',
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) {
logger.error('Failed to encrypt JWT:', e)
throw e
}
}

View File

@ -0,0 +1,18 @@
// import { JWTPayload } from 'jose'
import { JwtPayloadType } from './JwtPayloadType'
export class OpenConnectionJwtPayloadType extends JwtPayloadType {
static OPEN_CONNECTION_TYPE = 'open-connection'
url: string
constructor(
url: string,
) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
super()
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
this.tokentype = OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE
this.url = url
}
}

View File

@ -9,6 +9,9 @@ import { ensureUrlEndsWithSlash } from '@/util/utilities'
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,
@ -36,14 +39,22 @@ export async function startCommunityAuthentication(
const client = AuthenticationClientFactory.getInstance(foreignFedCom)
if (client instanceof V1_0_AuthenticationClient) {
if (!foreignCom.publicJwtKey) {
throw new Error('Public JWT key not found for foreign community')
}
const args = new OpenConnectionArgs()
args.publicKey = homeCom.publicKey.toString('hex')
// TODO encrypt url with foreignCom.publicKey and sign it with homeCom.privateKey
args.url = ensureUrlEndsWithSlash(homeFedCom.endPoint).concat(homeFedCom.apiVersion)
//create JWT with url in payload encrypted by foreignCom.publicKey and signed with homeCom.privateKey
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
logger.debug(
'Authentication: before client.openConnection() args:',
homeCom.publicKey.toString('hex'),
args.url,
args.jwt,
)
if (await client.openConnection(args)) {
logger.debug(`Authentication: successful initiated at community:`, foreignFedCom.endPoint)

View File

@ -6,5 +6,5 @@ export class OpenConnectionArgs {
publicKey: string
@Field(() => String)
url: string
jwt: string
}

View File

@ -3,4 +3,5 @@ export interface PublicCommunityInfo {
description: string
creationDate: Date
publicKey: string
publicJwtKey: string
}

View File

@ -7,6 +7,7 @@ export const getPublicCommunityInfo = gql`
description
creationDate
publicKey
publicJwtKey
}
}
`

View File

@ -37,6 +37,7 @@ export async function startValidateCommunities(timerInterval: number): Promise<v
}
export async function validateCommunities(): Promise<void> {
// search all foreign federated communities which are still not verified or have not been verified since last dht-announcement
const dbFederatedCommunities: DbFederatedCommunity[] =
await DbFederatedCommunity.createQueryBuilder()
.where({ foreign: true, verifiedAt: IsNull() })
@ -104,12 +105,14 @@ export async function writeJwtKeyPairInHomeCommunity(): Promise<DbCommunity> {
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity publicKey=`, publicKeyPem);
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity privateKey=`, privateKeyPem);
homeCom.publicJwtKey = Buffer.from(publicKeyPem);
homeCom.publicJwtKey = publicKeyPem;
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity publicJwtKey.length=`, homeCom.publicJwtKey.length);
homeCom.privateJwtKey = Buffer.from(privateKeyPem);
homeCom.privateJwtKey = privateKeyPem;
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity privateJwtKey.length=`, homeCom.privateJwtKey.length);
await DbCommunity.save(homeCom)
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity done`)
} else {
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity: keypair already exists`)
}
} else {
throw new Error(`Error! A HomeCommunity-Entry still not exist! Please start the DHT-Modul first.`)
@ -141,6 +144,7 @@ async function writeForeignCommunity(
com.foreign = true
com.name = pubInfo.name
com.publicKey = dbCom.publicKey
com.publicJwtKey = pubInfo.publicJwtKey
com.url = dbCom.endPoint
await DbCommunity.save(com)
}

View File

@ -12,6 +12,7 @@ export class GetPublicCommunityInfoResultLoggingView extends AbstractLoggingView
description: this.self.description,
creationDate: this.dateToString(this.self.creationDate),
publicKey: this.self.publicKey,
publicJwtKey: this.self.publicJwtKey,
}
}
}

View File

@ -6,6 +6,9 @@ import { Field, ObjectType } from 'type-graphql'
export class GetPublicCommunityInfoResult {
constructor(dbCom: DbCommunity) {
this.publicKey = dbCom.publicKey.toString('hex')
if (dbCom.publicJwtKey) {
this.publicJwtKey = dbCom.publicJwtKey
}
this.name = dbCom.name
this.description = dbCom.description
this.creationDate = dbCom.creationDate
@ -22,4 +25,7 @@ export class GetPublicCommunityInfoResult {
@Field(() => String)
publicKey: string
@Field(() => String)
publicJwtKey: string
}