Refactor de las rutas para lanzarse con node (sin tsx)
This commit is contained in:
119
packages/sim-shared/domain/JWT.ts
Normal file
119
packages/sim-shared/domain/JWT.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { sign } from "node:crypto"
|
||||
|
||||
export type JWTHeader = {
|
||||
alg: string,
|
||||
typ: string,
|
||||
kid: string
|
||||
}
|
||||
|
||||
export type JWTPayload<T> = {
|
||||
/** (Issuer) Quién emitió el token */
|
||||
iss?: string;
|
||||
|
||||
/** (Subject) De quién trata el token (ej. user_id) */
|
||||
sub?: string;
|
||||
|
||||
/** (Audience) Destinatarios del token */
|
||||
aud?: string | string[];
|
||||
|
||||
/** (Expiration Time) Fecha de expiración (Unix timestamp) */
|
||||
exp?: number;
|
||||
|
||||
/** (Not Before) No válido antes de esta fecha (Unix timestamp) */
|
||||
nbf?: number;
|
||||
|
||||
/** (Issued At) Cuándo fue emitido (Unix timestamp) */
|
||||
iat?: number;
|
||||
|
||||
/** (JWT ID) Identificador único para este token */
|
||||
jti?: string;
|
||||
|
||||
/** (Authentication Context Class) */
|
||||
acr?: string
|
||||
} & T
|
||||
|
||||
export type JWTSignature = {
|
||||
e?: string,
|
||||
ktv?: string,
|
||||
n?: string
|
||||
}
|
||||
|
||||
export type JWT<T> = {
|
||||
header: JWTHeader,
|
||||
payload?: JWTPayload<T>,
|
||||
signature: JWTSignature
|
||||
}
|
||||
|
||||
// todo pasar a la clase JWT
|
||||
function signJWT(args: {
|
||||
algorythm: "sha256" | string,
|
||||
data: string,
|
||||
privateKey: string
|
||||
}) {
|
||||
const signature = sign(
|
||||
args.algorythm,
|
||||
Buffer.from(args.data),
|
||||
args.privateKey
|
||||
)
|
||||
return signature
|
||||
}
|
||||
|
||||
export class JWTToken<T> {
|
||||
|
||||
public rawToken: string
|
||||
private decodedPayload: JWTPayload<T> | undefined
|
||||
|
||||
constructor(
|
||||
token: string
|
||||
) {
|
||||
this.rawToken = token
|
||||
this.decodedPayload = this.decodePayload()
|
||||
}
|
||||
|
||||
public static fromParts<T>(args: {
|
||||
header: JWTHeader,
|
||||
payload?: JWTPayload<T>,
|
||||
sigantureData?: {
|
||||
privateKey: string,
|
||||
algorythm: string
|
||||
}
|
||||
}) {
|
||||
const strHeader = JSON.stringify(args.header)
|
||||
const base64Header = Buffer.from(strHeader).toString("base64url")
|
||||
let token = base64Header
|
||||
|
||||
if (args.payload != undefined) {
|
||||
const strPayload = JSON.stringify(args.payload)
|
||||
const base64payload = Buffer.from(strPayload).toString("base64url")
|
||||
token += ("." + base64payload)
|
||||
}
|
||||
|
||||
if (args.sigantureData != undefined) {
|
||||
const base64signature = signJWT({
|
||||
algorythm: args.sigantureData.algorythm,
|
||||
privateKey: args.sigantureData.privateKey,
|
||||
data: token
|
||||
}).toString("base64url")
|
||||
token += ("." + base64signature)
|
||||
}
|
||||
|
||||
return token
|
||||
|
||||
}
|
||||
|
||||
private decodePayload(): JWTPayload<T> {
|
||||
if (this.rawToken == undefined) throw new Error("La clase no tiene un token definido")
|
||||
const rawTokenPayload = this.rawToken.split(".")[1]
|
||||
if (rawTokenPayload == undefined) throw new Error("El token no tiene payload")
|
||||
return JSON.parse(Buffer.from(rawTokenPayload, "base64").toString("utf8"));
|
||||
}
|
||||
|
||||
public isExpired() {
|
||||
if (this.decodedPayload == undefined) throw new Error("Error leyendo el payload del token")
|
||||
const now = new Date()
|
||||
const expirationDate = this.decodedPayload.exp
|
||||
if (expirationDate == undefined) return false // un token sin fecha de expiracion no expira
|
||||
if (expirationDate * 1000 <= now.getTime()) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user