mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
shift JWT-files to core
This commit is contained in:
parent
0c9296db44
commit
2c92629174
@ -1,158 +0,0 @@
|
||||
|
||||
// import { testEnvironment } from '@test/helpers'
|
||||
// import { logger } from '@test/testSetup'
|
||||
|
||||
import { createKeyPair, decode, decrypt, encode, encrypt, encryptAndSign, verify, verifyAndDecrypt } from './JWT'
|
||||
import { EncryptedJWEJwtPayloadType } from './payloadtypes/EncryptedJWEJwtPayloadType'
|
||||
import { OpenConnectionJwtPayloadType } from './payloadtypes/OpenConnectionJwtPayloadType'
|
||||
|
||||
// let con: DataSource
|
||||
// let testEnv: {
|
||||
// mutate: ApolloServerTestClient['mutate']
|
||||
// query: ApolloServerTestClient['query']
|
||||
// con: DataSource
|
||||
// }
|
||||
let keypairComA: { publicKey: string; privateKey: string }
|
||||
let keypairComB: { publicKey: string; privateKey: string }
|
||||
|
||||
beforeAll(async () => {
|
||||
// testEnv = await testEnvironment(logger)
|
||||
// con = testEnv.con
|
||||
// await cleanDB()
|
||||
|
||||
keypairComA = await createKeyPair()
|
||||
keypairComB = await createKeyPair()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
// await cleanDB()
|
||||
// await con.destroy()
|
||||
})
|
||||
|
||||
describe('test JWS creation and verification', () => {
|
||||
let jwsComA: string
|
||||
let jwsComB: string
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
jwsComA = await encode(new OpenConnectionJwtPayloadType('http://localhost:5001/api/'), keypairComA.privateKey)
|
||||
jwsComB = await encode(new OpenConnectionJwtPayloadType('http://localhost:5002/api/'), keypairComB.privateKey)
|
||||
})
|
||||
it('decode jwsComA', async () => {
|
||||
const decodedJwsComA = await decode(jwsComA)
|
||||
expect(decodedJwsComA).toEqual({
|
||||
expiration: '10m',
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
url: 'http://localhost:5001/api/',
|
||||
})
|
||||
})
|
||||
it('decode jwsComB', async () => {
|
||||
const decodedJwsComB = await decode(jwsComB)
|
||||
expect(decodedJwsComB).toEqual({
|
||||
expiration: '10m',
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
url: 'http://localhost:5002/api/',
|
||||
})
|
||||
})
|
||||
it('verify jwsComA', async () => {
|
||||
const verifiedJwsComA = await verify(jwsComA, keypairComA.publicKey)
|
||||
expect(verifiedJwsComA).toEqual(expect.objectContaining({
|
||||
payload: expect.objectContaining({
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
url: 'http://localhost:5001/api/',
|
||||
})
|
||||
}))
|
||||
})
|
||||
it('verify jwsComB', async () => {
|
||||
const verifiedJwsComB = await verify(jwsComB, keypairComB.publicKey)
|
||||
expect(verifiedJwsComB).toEqual(expect.objectContaining({
|
||||
payload: expect.objectContaining({
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
url: 'http://localhost:5002/api/',
|
||||
})
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
describe('test JWE encryption and decryption', () => {
|
||||
let jweComA: string
|
||||
let jweComB: string
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
jweComA = await encrypt(new OpenConnectionJwtPayloadType('http://localhost:5001/api/'), keypairComB.publicKey)
|
||||
jweComB = await encrypt(new OpenConnectionJwtPayloadType('http://localhost:5002/api/'), keypairComA.publicKey)
|
||||
})
|
||||
it('decrypt jweComA', async () => {
|
||||
const decryptedAJwT = await decrypt(jweComA, keypairComB.privateKey)
|
||||
expect(JSON.parse(decryptedAJwT)).toEqual(expect.objectContaining({
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
url: 'http://localhost:5001/api/',
|
||||
}))
|
||||
})
|
||||
it('decrypt jweComB', async () => {
|
||||
const decryptedBJwT = await decrypt(jweComB, keypairComA.privateKey)
|
||||
expect(JSON.parse(decryptedBJwT)).toEqual(expect.objectContaining({
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
url: 'http://localhost:5002/api/',
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
describe('test encrypted and signed JWT', () => {
|
||||
let jweComA: string
|
||||
let jwsComA: string
|
||||
let jweComB: string
|
||||
let jwsComB: string
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
jweComA = await encrypt(new OpenConnectionJwtPayloadType('http://localhost:5001/api/'), keypairComB.publicKey)
|
||||
jwsComA = await encode(new EncryptedJWEJwtPayloadType(jweComA), keypairComA.privateKey)
|
||||
jweComB = await encrypt(new OpenConnectionJwtPayloadType('http://localhost:5002/api/'), keypairComA.publicKey)
|
||||
jwsComB = await encode(new EncryptedJWEJwtPayloadType(jweComB), keypairComB.privateKey)
|
||||
})
|
||||
it('verify jwsComA', async () => {
|
||||
const verifiedJwsComA = await verify(jwsComA, keypairComA.publicKey)
|
||||
expect(verifiedJwsComA).toEqual(expect.objectContaining({
|
||||
payload: expect.objectContaining({
|
||||
jwe: jweComA,
|
||||
tokentype: EncryptedJWEJwtPayloadType.ENCRYPTED_JWE_TYPE,
|
||||
})
|
||||
}))
|
||||
})
|
||||
it('verify jwsComB', async () => {
|
||||
const verifiedJwsComB = await verify(jwsComB, keypairComB.publicKey)
|
||||
expect(verifiedJwsComB).toEqual(expect.objectContaining({
|
||||
payload: expect.objectContaining({
|
||||
jwe: jweComB,
|
||||
tokentype: EncryptedJWEJwtPayloadType.ENCRYPTED_JWE_TYPE,
|
||||
})
|
||||
}))
|
||||
})
|
||||
it('decrypt jweComA', async () => {
|
||||
expect(JSON.parse(await decrypt(jweComA, keypairComB.privateKey))).toEqual(expect.objectContaining({
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
url: 'http://localhost:5001/api/',
|
||||
}))
|
||||
})
|
||||
it('decrypt jweComB', async () => {
|
||||
expect(JSON.parse(await decrypt(jweComB, keypairComA.privateKey))).toEqual(expect.objectContaining({
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
url: 'http://localhost:5002/api/',
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('test encryptAndSign and verifyAndDecrypt', () => {
|
||||
let jwtComA: string
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
jwtComA = await encryptAndSign(new OpenConnectionJwtPayloadType('http://localhost:5001/api/'), keypairComA.privateKey, keypairComB.publicKey)
|
||||
})
|
||||
it('verifyAndDecrypt jwtComA', async () => {
|
||||
const verifiedAndDecryptedPayload = await verifyAndDecrypt(jwtComA, keypairComB.privateKey, keypairComA.publicKey)
|
||||
expect(verifiedAndDecryptedPayload).toEqual(expect.objectContaining({
|
||||
tokentype: OpenConnectionJwtPayloadType.OPEN_CONNECTION_TYPE,
|
||||
url: 'http://localhost:5001/api/',
|
||||
}))
|
||||
})
|
||||
})
|
||||
@ -1,150 +0,0 @@
|
||||
import { generateKeyPair, exportSPKI, exportPKCS8, SignJWT, decodeJwt, importPKCS8, importSPKI, jwtVerify, CompactEncrypt, compactDecrypt } from 'jose'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import { getLogger } from 'log4js'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.auth.jwt.JWT`)
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
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
|
||||
const keyPair = await generateKeyPair('RS256');
|
||||
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity generated keypair...`);
|
||||
|
||||
// Convert keys to PEM format for storage in database
|
||||
const publicKeyPem = await exportSPKI(keyPair.publicKey);
|
||||
const privateKeyPem = await exportPKCS8(keyPair.privateKey);
|
||||
return { publicKey: publicKeyPem, privateKey: privateKeyPem };
|
||||
}
|
||||
|
||||
export const verify = async (token: string, publicKey: string): Promise<JwtPayloadType | null> => {
|
||||
if (!token) {
|
||||
throw new LogError('401 Unauthorized')
|
||||
}
|
||||
logger.debug('JWT.verify... token, publicKey=', token, publicKey)
|
||||
|
||||
try {
|
||||
const importedKey = await importSPKI(publicKey, 'RS256')
|
||||
// Convert the key to JWK format if needed
|
||||
const secret = typeof importedKey === 'string'
|
||||
? JSON.parse(importedKey)
|
||||
: importedKey;
|
||||
// const secret = new TextEncoder().encode(publicKey)
|
||||
const { payload } = await jwtVerify(token, secret, {
|
||||
issuer: JwtPayloadType.ISSUER,
|
||||
audience: JwtPayloadType.AUDIENCE,
|
||||
})
|
||||
logger.debug('JWT.verify after jwtVerify... payload=', payload)
|
||||
return payload as JwtPayloadType
|
||||
} catch (err) {
|
||||
logger.error('JWT.verify after jwtVerify... error=', err)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export const encode = async (payload: JwtPayloadType, privatekey: string): Promise<string> => {
|
||||
logger.debug('JWT.encode... payload=', payload)
|
||||
logger.debug('JWT.encode... privatekey=', privatekey.substring(0, 10))
|
||||
try {
|
||||
const importedKey = await importPKCS8(privatekey, 'RS256')
|
||||
const secret = typeof importedKey === 'string'
|
||||
? JSON.parse(importedKey)
|
||||
: importedKey;
|
||||
|
||||
// const secret = new TextEncoder().encode(privatekey)
|
||||
const token = await new SignJWT({ payload, 'urn:gradido:claim': true })
|
||||
.setProtectedHeader({
|
||||
alg: 'RS256',
|
||||
})
|
||||
.setIssuedAt()
|
||||
.setIssuer(JwtPayloadType.ISSUER)
|
||||
.setAudience(JwtPayloadType.AUDIENCE)
|
||||
.setExpirationTime(payload.expiration)
|
||||
.sign(secret)
|
||||
return token
|
||||
} catch (e) {
|
||||
logger.error('Failed to sign JWT:', e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
export const verifyJwtType = async (token: string, publicKey: string): Promise<string> => {
|
||||
const payload = await verify(token, publicKey)
|
||||
return payload ? payload.tokentype : 'unknown token type'
|
||||
}
|
||||
|
||||
export const decode = (token: string): JwtPayloadType => {
|
||||
const { payload } = decodeJwt(token)
|
||||
return payload as JwtPayloadType
|
||||
}
|
||||
|
||||
export const encrypt = async (payload: JwtPayloadType, publicKey: string): Promise<string> => {
|
||||
logger.debug('JWT.encrypt... payload=', payload)
|
||||
logger.debug('JWT.encrypt... publicKey=', publicKey)
|
||||
try {
|
||||
const encryptKey = await importSPKI(publicKey, 'RSA-OAEP-256')
|
||||
// Convert the key to JWK format if needed
|
||||
const recipientKey = typeof encryptKey === 'string'
|
||||
? JSON.parse(encryptKey)
|
||||
: encryptKey;
|
||||
|
||||
const jwe = await new CompactEncrypt(
|
||||
new TextEncoder().encode(JSON.stringify(payload)),
|
||||
)
|
||||
.setProtectedHeader({ alg: 'RSA-OAEP-256', enc: 'A256GCM' })
|
||||
.encrypt(recipientKey)
|
||||
logger.debug('JWT.encrypt... jwe=', jwe)
|
||||
return jwe.toString()
|
||||
} catch (e) {
|
||||
logger.error('Failed to encrypt JWT:', e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
export const decrypt = async(jwe: string, privateKey: string): Promise<string> => {
|
||||
logger.debug('JWT.decrypt... jwe=', jwe)
|
||||
logger.debug('JWT.decrypt... privateKey=', privateKey.substring(0, 10))
|
||||
try {
|
||||
const decryptKey = await importPKCS8(privateKey, 'RSA-OAEP-256')
|
||||
const { plaintext, protectedHeader } =
|
||||
await compactDecrypt(jwe, decryptKey)
|
||||
logger.debug('JWT.decrypt... plaintext=', plaintext)
|
||||
logger.debug('JWT.decrypt... protectedHeader=', protectedHeader)
|
||||
return new TextDecoder().decode(plaintext)
|
||||
} 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)
|
||||
logger.debug('JWT.encryptAndSign... jwe=', jwe)
|
||||
const jws = await encode(new EncryptedJWEJwtPayloadType(jwe), privateKey)
|
||||
logger.debug('JWT.encryptAndSign... jws=', jws)
|
||||
return jws
|
||||
}
|
||||
|
||||
export const verifyAndDecrypt = async (token: string, privateKey: string, publicKey: string): Promise<JwtPayloadType | null> => {
|
||||
const jweVerifyResult = await verify(token, publicKey)
|
||||
if (!jweVerifyResult) {
|
||||
return null
|
||||
}
|
||||
const jwePayload = jweVerifyResult.payload as EncryptedJWEJwtPayloadType
|
||||
logger.debug('JWT.verifyAndDecrypt... jwePayload=', jwePayload)
|
||||
if (!jwePayload) {
|
||||
return null
|
||||
}
|
||||
const jwePayloadType = jwePayload.tokentype
|
||||
if (jwePayloadType !== EncryptedJWEJwtPayloadType.ENCRYPTED_JWE_TYPE) {
|
||||
return null
|
||||
}
|
||||
const jwe = jwePayload.jwe
|
||||
logger.debug('JWT.verifyAndDecrypt... jwe=', jwe)
|
||||
const payload = await decrypt(jwe as string, privateKey)
|
||||
logger.debug('JWT.verifyAndDecrypt... payload=', payload)
|
||||
return JSON.parse(payload) as JwtPayloadType
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
// import { JWTPayload } from 'jose'
|
||||
import { JwtPayloadType } from './JwtPayloadType'
|
||||
|
||||
export class EncryptedJWEJwtPayloadType extends JwtPayloadType {
|
||||
static ENCRYPTED_JWE_TYPE = 'encrypted-jwe'
|
||||
|
||||
jwe: string
|
||||
|
||||
constructor(
|
||||
jwe: string,
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
super()
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
this.tokentype = EncryptedJWEJwtPayloadType.ENCRYPTED_JWE_TYPE
|
||||
this.jwe = jwe
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
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
|
||||
jti?: string | undefined
|
||||
aud?: string | string[] | undefined
|
||||
sub?: string | undefined
|
||||
iss?: string | undefined;
|
||||
[propName: string]: unknown
|
||||
|
||||
tokentype: string
|
||||
expiration: string // in minutes (format: 10m for ten minutes)
|
||||
constructor() {
|
||||
this.tokentype = 'unknown jwt type'
|
||||
this.expiration = CONFIG.REDEEM_JWT_TOKEN_EXPIRATION || '10m'
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
// import { JWTPayload } from 'jose'
|
||||
import { JwtPayloadType } from './JwtPayloadType'
|
||||
|
||||
export class RedeemJwtPayloadType extends JwtPayloadType {
|
||||
static REDEEM_ACTIVATION_TYPE = 'redeem-activation'
|
||||
|
||||
sendercommunityuuid: string
|
||||
sendergradidoid: string
|
||||
sendername: string // alias or firstname
|
||||
redeemcode: string
|
||||
amount: string
|
||||
memo: string
|
||||
validuntil: string
|
||||
|
||||
constructor(
|
||||
senderCom: string,
|
||||
senderUser: string,
|
||||
sendername: string,
|
||||
code: string,
|
||||
amount: string,
|
||||
memo: string,
|
||||
validUntil: string,
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
super()
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
this.tokentype = RedeemJwtPayloadType.REDEEM_ACTIVATION_TYPE
|
||||
this.sendercommunityuuid = senderCom
|
||||
this.sendergradidoid = senderUser
|
||||
this.sendername = sendername
|
||||
this.redeemcode = code
|
||||
this.amount = amount
|
||||
this.memo = memo
|
||||
this.validuntil = validUntil
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,17 @@
|
||||
import { generateKeyPair, exportSPKI, exportPKCS8, SignJWT, decodeJwt, importPKCS8, importSPKI, jwtVerify, CompactEncrypt, compactDecrypt } from 'jose'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '../../config/const'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import { getLogger } from 'log4js'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.auth.jwt.JWT`)
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
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
|
||||
const keyPair = await generateKeyPair('RS256', {
|
||||
modulusLength: 2048, // recommended key size
|
||||
extractable: true,
|
||||
});
|
||||
const keyPair = await generateKeyPair('RS256');
|
||||
logger.debug(`Federation: writeJwtKeyPairInHomeCommunity generated keypair...`);
|
||||
|
||||
// Convert keys to PEM format for storage in database
|
||||
@ -23,10 +22,9 @@ export const createKeyPair = async (): Promise<{ publicKey: string; privateKey:
|
||||
|
||||
export const verify = async (token: string, publicKey: string): Promise<JwtPayloadType | null> => {
|
||||
if (!token) {
|
||||
logger.error('verify... token is empty')
|
||||
throw new Error('401 Unauthorized')
|
||||
throw new LogError('401 Unauthorized')
|
||||
}
|
||||
logger.debug('verify... token, publicKey=', token, publicKey)
|
||||
logger.debug('JWT.verify... token, publicKey=', token, publicKey)
|
||||
|
||||
try {
|
||||
const importedKey = await importSPKI(publicKey, 'RS256')
|
||||
@ -39,17 +37,17 @@ export const verify = async (token: string, publicKey: string): Promise<JwtPaylo
|
||||
issuer: JwtPayloadType.ISSUER,
|
||||
audience: JwtPayloadType.AUDIENCE,
|
||||
})
|
||||
logger.debug('verify after jwtVerify... payload=', payload)
|
||||
logger.debug('JWT.verify after jwtVerify... payload=', payload)
|
||||
return payload as JwtPayloadType
|
||||
} catch (err) {
|
||||
logger.error('verify after jwtVerify... error=', err)
|
||||
logger.error('JWT.verify after jwtVerify... error=', err)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export const encode = async (payload: JwtPayloadType, privatekey: string): Promise<string> => {
|
||||
logger.debug('encode... payload=', payload)
|
||||
logger.debug('encode... privatekey=', privatekey.substring(0, 10))
|
||||
logger.debug('JWT.encode... payload=', payload)
|
||||
logger.debug('JWT.encode... privatekey=', privatekey.substring(0, 10))
|
||||
try {
|
||||
const importedKey = await importPKCS8(privatekey, 'RS256')
|
||||
const secret = typeof importedKey === 'string'
|
||||
@ -84,8 +82,8 @@ export const decode = (token: string): JwtPayloadType => {
|
||||
}
|
||||
|
||||
export const encrypt = async (payload: JwtPayloadType, publicKey: string): Promise<string> => {
|
||||
logger.debug('encrypt... payload=', payload)
|
||||
logger.debug('encrypt... publicKey=', publicKey)
|
||||
logger.debug('JWT.encrypt... payload=', payload)
|
||||
logger.debug('JWT.encrypt... publicKey=', publicKey)
|
||||
try {
|
||||
const encryptKey = await importSPKI(publicKey, 'RSA-OAEP-256')
|
||||
// Convert the key to JWK format if needed
|
||||
@ -98,7 +96,7 @@ export const encrypt = async (payload: JwtPayloadType, publicKey: string): Promi
|
||||
)
|
||||
.setProtectedHeader({ alg: 'RSA-OAEP-256', enc: 'A256GCM' })
|
||||
.encrypt(recipientKey)
|
||||
logger.debug('encrypt... jwe=', jwe)
|
||||
logger.debug('JWT.encrypt... jwe=', jwe)
|
||||
return jwe.toString()
|
||||
} catch (e) {
|
||||
logger.error('Failed to encrypt JWT:', e)
|
||||
@ -107,14 +105,14 @@ export const encrypt = async (payload: JwtPayloadType, publicKey: string): Promi
|
||||
}
|
||||
|
||||
export const decrypt = async(jwe: string, privateKey: string): Promise<string> => {
|
||||
logger.debug('decrypt... jwe=', jwe)
|
||||
logger.debug('decrypt... privateKey=', privateKey.substring(0, 10))
|
||||
logger.debug('JWT.decrypt... jwe=', jwe)
|
||||
logger.debug('JWT.decrypt... privateKey=', privateKey.substring(0, 10))
|
||||
try {
|
||||
const decryptKey = await importPKCS8(privateKey, 'RSA-OAEP-256')
|
||||
const { plaintext, protectedHeader } =
|
||||
await compactDecrypt(jwe, decryptKey)
|
||||
logger.debug('decrypt... plaintext=', plaintext)
|
||||
logger.debug('decrypt... protectedHeader=', protectedHeader)
|
||||
logger.debug('JWT.decrypt... plaintext=', plaintext)
|
||||
logger.debug('JWT.decrypt... protectedHeader=', protectedHeader)
|
||||
return new TextDecoder().decode(plaintext)
|
||||
} catch (e) {
|
||||
logger.error('Failed to decrypt JWT:', e)
|
||||
@ -124,9 +122,9 @@ export const decrypt = async(jwe: string, privateKey: string): Promise<string> =
|
||||
|
||||
export const encryptAndSign = async (payload: JwtPayloadType, privateKey: string, publicKey: string): Promise<string> => {
|
||||
const jwe = await encrypt(payload, publicKey)
|
||||
logger.debug('encryptAndSign... jwe=', jwe)
|
||||
logger.debug('JWT.encryptAndSign... jwe=', jwe)
|
||||
const jws = await encode(new EncryptedJWEJwtPayloadType(jwe), privateKey)
|
||||
logger.debug('encryptAndSign... jws=', jws)
|
||||
logger.debug('JWT.encryptAndSign... jws=', jws)
|
||||
return jws
|
||||
}
|
||||
|
||||
@ -136,7 +134,7 @@ export const verifyAndDecrypt = async (token: string, privateKey: string, public
|
||||
return null
|
||||
}
|
||||
const jwePayload = jweVerifyResult.payload as EncryptedJWEJwtPayloadType
|
||||
logger.debug('verifyAndDecrypt... jwePayload=', jwePayload)
|
||||
logger.debug('JWT.verifyAndDecrypt... jwePayload=', jwePayload)
|
||||
if (!jwePayload) {
|
||||
return null
|
||||
}
|
||||
@ -145,8 +143,8 @@ export const verifyAndDecrypt = async (token: string, privateKey: string, public
|
||||
return null
|
||||
}
|
||||
const jwe = jwePayload.jwe
|
||||
logger.debug('verifyAndDecrypt... jwe=', jwe)
|
||||
logger.debug('JWT.verifyAndDecrypt... jwe=', jwe)
|
||||
const payload = await decrypt(jwe as string, privateKey)
|
||||
logger.debug('verifyAndDecrypt... payload=', payload)
|
||||
logger.debug('JWT.verifyAndDecrypt... payload=', payload)
|
||||
return JSON.parse(payload) as JwtPayloadType
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
// import { JWTPayload } from 'jose'
|
||||
import { JwtPayloadType } from './JwtPayloadType'
|
||||
|
||||
export class EncryptedJWEJwtPayloadType extends JwtPayloadType {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { JWTPayload } from 'jose'
|
||||
|
||||
import { REDEEM_JWT_TOKEN_EXPIRATION } from '../../../config/const'
|
||||
import { CONFIG } from '@/config'
|
||||
|
||||
export class JwtPayloadType implements JWTPayload {
|
||||
static ISSUER = 'urn:gradido:issuer'
|
||||
@ -19,6 +19,6 @@ export class JwtPayloadType implements JWTPayload {
|
||||
expiration: string // in minutes (format: 10m for ten minutes)
|
||||
constructor() {
|
||||
this.tokentype = 'unknown jwt type'
|
||||
this.expiration = REDEEM_JWT_TOKEN_EXPIRATION || '10m'
|
||||
this.expiration = CONFIG.REDEEM_JWT_TOKEN_EXPIRATION || '10m'
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,9 +6,9 @@ import { CommunityLoggingView, getHomeCommunity } from 'database'
|
||||
import { verifyAndDecrypt } from '../../auth/jwt/JWT'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '../../config/const'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.logic.interpretEncryptedTransferArgs`)
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.util.interpretEncryptedTransferArgs`)
|
||||
|
||||
export const interpretEncryptedTransferArgs = async (args: EncryptedTransferArgs): Promise<{ jwtPayload: JwtPayloadType, comA: DbCommunity } | null> => {
|
||||
export const interpretEncryptedTransferArgs = async (args: EncryptedTransferArgs): Promise<JwtPayloadType | null> => {
|
||||
const pubKeyBuf = Buffer.from(args.publicKey, 'hex')
|
||||
|
||||
// first find with args.publicKey the community 'comA', which starts openConnection request
|
||||
@ -32,5 +32,5 @@ export const interpretEncryptedTransferArgs = async (args: EncryptedTransferArgs
|
||||
logger.error(errmsg)
|
||||
throw new Error(errmsg)
|
||||
}
|
||||
return { jwtPayload, comA }
|
||||
return jwtPayload
|
||||
}
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
import { Field, InputType } from 'type-graphql'
|
||||
|
||||
@InputType()
|
||||
export class OpenConnectionArgs {
|
||||
@Field(() => String)
|
||||
publicKey: string
|
||||
|
||||
@Field(() => String)
|
||||
jwt: string
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
import { Field, InputType } from 'type-graphql'
|
||||
|
||||
@InputType()
|
||||
export class OpenConnectionCallbackArgs {
|
||||
@Field(() => String)
|
||||
oneTimeCode: string
|
||||
|
||||
@Field(() => String)
|
||||
url: string
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user