PrivateKeyPem

This commit is contained in:
tamaina 2024-03-05 15:53:24 +00:00
parent 834f46537d
commit 689a9ce5f9
12 changed files with 41 additions and 47 deletions

View file

@ -79,7 +79,7 @@
"@fastify/multipart": "8.1.0", "@fastify/multipart": "8.1.0",
"@fastify/static": "6.12.0", "@fastify/static": "6.12.0",
"@fastify/view": "8.2.0", "@fastify/view": "8.2.0",
"@misskey-dev/node-http-message-signatures": "0.0.3", "@misskey-dev/node-http-message-signatures": "0.0.4",
"@misskey-dev/sharp-read-bmp": "1.2.0", "@misskey-dev/sharp-read-bmp": "1.2.0",
"@misskey-dev/summaly": "5.0.3", "@misskey-dev/summaly": "5.0.3",
"@nestjs/common": "10.3.3", "@nestjs/common": "10.3.3",

View file

@ -13,7 +13,7 @@ import { RelayService } from '@/core/RelayService.js';
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js'; import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import type { PrivateKey } from './activitypub/type.js'; import type { PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures';
@Injectable() @Injectable()
export class AccountUpdateService implements OnModuleInit { export class AccountUpdateService implements OnModuleInit {
@ -40,7 +40,7 @@ export class AccountUpdateService implements OnModuleInit {
* @param userId ID * @param userId ID
* @param isKeyUpdation Ed25519キーの作成など公開鍵のアップデートによる呼び出しか trueにするとメインキーを使うようになる * @param isKeyUpdation Ed25519キーの作成など公開鍵のアップデートによる呼び出しか trueにするとメインキーを使うようになる
*/ */
public async publishToFollowers(userId: MiUser['id'], deliverKey?: PrivateKey) { public async publishToFollowers(userId: MiUser['id'], deliverKey?: PrivateKeyWithPem) {
const user = await this.usersRepository.findOneBy({ id: userId }); const user = await this.usersRepository.findOneBy({ id: userId });
if (user == null) throw new Error('user not found'); if (user == null) throw new Error('user not found');

View file

@ -5,7 +5,7 @@
import { randomUUID } from 'node:crypto'; import { randomUUID } from 'node:crypto';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import type { IActivity, PrivateKey } from '@/core/activitypub/type.js'; import type { IActivity } from '@/core/activitypub/type.js';
import type { MiDriveFile } from '@/models/DriveFile.js'; import type { MiDriveFile } from '@/models/DriveFile.js';
import type { MiWebhook, webhookEventTypes } from '@/models/Webhook.js'; import type { MiWebhook, webhookEventTypes } from '@/models/Webhook.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
@ -15,7 +15,7 @@ import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js';
import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, RelationshipQueue, SystemQueue, WebhookDeliverQueue } from './QueueModule.js'; import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, RelationshipQueue, SystemQueue, WebhookDeliverQueue } from './QueueModule.js';
import type { DbJobData, DeliverJobData, RelationshipJobData, ThinUser } from '../queue/types.js'; import type { DbJobData, DeliverJobData, RelationshipJobData, ThinUser } from '../queue/types.js';
import type * as Bull from 'bullmq'; import type * as Bull from 'bullmq';
import { genRFC3230DigestHeader, type ParsedSignature } from '@misskey-dev/node-http-message-signatures'; import { genRFC3230DigestHeader, type PrivateKeyWithPem, type ParsedSignature } from '@misskey-dev/node-http-message-signatures';
@Injectable() @Injectable()
export class QueueService { export class QueueService {
@ -70,7 +70,7 @@ export class QueueService {
} }
@bindThis @bindThis
public async deliver(user: ThinUser, content: IActivity | null, to: string | null, isSharedInbox: boolean, privateKey?: PrivateKey) { public async deliver(user: ThinUser, content: IActivity | null, to: string | null, isSharedInbox: boolean, privateKey?: PrivateKeyWithPem) {
if (content == null) return null; if (content == null) return null;
if (to == null) return null; if (to == null) return null;
@ -84,7 +84,7 @@ export class QueueService {
digest: await genRFC3230DigestHeader(contentBody, 'SHA-256'), digest: await genRFC3230DigestHeader(contentBody, 'SHA-256'),
to, to,
isSharedInbox, isSharedInbox,
privateKey: privateKey && { keyId: privateKey.keyId, privateKey: privateKey.privateKey }, privateKey: privateKey && { keyId: privateKey.keyId, privateKeyPem: privateKey.privateKeyPem },
}; };
return this.deliverQueue.add(to, data, { return this.deliverQueue.add(to, data, {
@ -106,7 +106,7 @@ export class QueueService {
* @returns void * @returns void
*/ */
@bindThis @bindThis
public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map<string, boolean>, privateKey?: PrivateKey) { public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map<string, boolean>, privateKey?: PrivateKeyWithPem) {
if (content == null) return null; if (content == null) return null;
const contentBody = JSON.stringify(content); const contentBody = JSON.stringify(content);
@ -126,7 +126,7 @@ export class QueueService {
content: contentBody, content: contentBody,
to: d[0], to: d[0],
isSharedInbox: d[1], isSharedInbox: d[1],
privateKey: privateKey && { keyId: privateKey.keyId, privateKey: privateKey.privateKey }, privateKey: privateKey && { keyId: privateKey.keyId, privateKeyPem: privateKey.privateKeyPem },
} as DeliverJobData, } as DeliverJobData,
opts, opts,
}))); })));

View file

@ -17,7 +17,7 @@ import { DI } from '@/di-symbols.js';
import { deepClone } from '@/misc/clone.js'; import { deepClone } from '@/misc/clone.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { UserKeypairService } from './UserKeypairService.js'; import { UserKeypairService } from './UserKeypairService.js';
import type { PrivateKey } from './activitypub/type.js'; import type { PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures';
const ACTOR_USERNAME = 'relay.actor' as const; const ACTOR_USERNAME = 'relay.actor' as const;
@ -114,7 +114,7 @@ export class RelayService {
} }
@bindThis @bindThis
public async deliverToRelays(user: { id: MiUser['id']; host: null; }, activity: any, privateKey?: PrivateKey): Promise<void> { public async deliverToRelays(user: { id: MiUser['id']; host: null; }, activity: any, privateKey?: PrivateKeyWithPem): Promise<void> {
if (activity == null) return; if (activity == null) return;
const relays = await this.relaysCache.fetch(() => this.relaysRepository.findBy({ const relays = await this.relaysCache.fetch(() => this.relaysRepository.findBy({
@ -124,7 +124,7 @@ export class RelayService {
const copy = deepClone(activity); const copy = deepClone(activity);
if (!copy.to) copy.to = ['https://www.w3.org/ns/activitystreams#Public']; if (!copy.to) copy.to = ['https://www.w3.org/ns/activitystreams#Public'];
privateKey = privateKey ?? await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id); privateKey = privateKey ?? await this.userKeypairService.getLocalUserPrivateKeyPem(user.id);
const signed = await this.apRendererService.attachLdSignature(copy, user, privateKey); const signed = await this.apRendererService.attachLdSignature(copy, user, privateKey);
this.queueService.deliverMany(user, signed, new Map(relays.map(({ inbox }) => [inbox, false])), privateKey); this.queueService.deliverMany(user, signed, new Map(relays.map(({ inbox }) => [inbox, false])), privateKey);

View file

@ -5,7 +5,7 @@
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
import * as Redis from 'ioredis'; import * as Redis from 'ioredis';
import { genEd25519KeyPair } from '@misskey-dev/node-http-message-signatures'; import { genEd25519KeyPair, PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures';
import type { MiUser } from '@/models/User.js'; import type { MiUser } from '@/models/User.js';
import type { UserKeypairsRepository } from '@/models/_.js'; import type { UserKeypairsRepository } from '@/models/_.js';
import { RedisKVCache } from '@/misc/cache.js'; import { RedisKVCache } from '@/misc/cache.js';
@ -53,9 +53,9 @@ export class UserKeypairService implements OnApplicationShutdown {
* @returns * @returns
*/ */
@bindThis @bindThis
public async getLocalUserKeypairWithKeyId( public async getLocalUserPrivateKeyPem(
userIdOrHint: MiUser['id'] | MiUserKeypair, preferType?: string, userIdOrHint: MiUser['id'] | MiUserKeypair, preferType?: string,
): Promise<{ keyId: string; publicKey: string; privateKey: string; }> { ): Promise<PrivateKeyWithPem> {
const keypair = typeof userIdOrHint === 'string' ? await this.getUserKeypair(userIdOrHint) : userIdOrHint; const keypair = typeof userIdOrHint === 'string' ? await this.getUserKeypair(userIdOrHint) : userIdOrHint;
if ( if (
preferType && ['01', '11', 'ed25519'].includes(preferType.toLowerCase()) && preferType && ['01', '11', 'ed25519'].includes(preferType.toLowerCase()) &&
@ -63,14 +63,12 @@ export class UserKeypairService implements OnApplicationShutdown {
) { ) {
return { return {
keyId: `${this.userEntityService.genLocalUserUri(keypair.userId)}#ed25519-key`, keyId: `${this.userEntityService.genLocalUserUri(keypair.userId)}#ed25519-key`,
publicKey: keypair.ed25519PublicKey, privateKeyPem: keypair.ed25519PrivateKey,
privateKey: keypair.ed25519PrivateKey,
}; };
} }
return { return {
keyId: `${this.userEntityService.genLocalUserUri(keypair.userId)}#main-key`, keyId: `${this.userEntityService.genLocalUserUri(keypair.userId)}#main-key`,
publicKey: keypair.publicKey, privateKeyPem: keypair.privateKey,
privateKey: keypair.privateKey,
}; };
} }

View file

@ -32,7 +32,7 @@ export class UserSuspendService {
const manager = this.apDeliverManagerService.createDeliverManager(user, content); const manager = this.apDeliverManagerService.createDeliverManager(user, content);
manager.addAllKnowingSharedInboxRecipe(); manager.addAllKnowingSharedInboxRecipe();
// process deliver時にはキーペアが消去されているはずなので、ここで挿入する // process deliver時にはキーペアが消去されているはずなので、ここで挿入する
const privateKey = await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id, 'main'); const privateKey = await this.userKeypairService.getLocalUserPrivateKeyPem(user.id, 'main');
manager.execute({ privateKey }); manager.execute({ privateKey });
} }
} }
@ -46,7 +46,7 @@ export class UserSuspendService {
const manager = this.apDeliverManagerService.createDeliverManager(user, content); const manager = this.apDeliverManagerService.createDeliverManager(user, content);
manager.addAllKnowingSharedInboxRecipe(); manager.addAllKnowingSharedInboxRecipe();
// process deliver時にはキーペアが消去されているはずなので、ここで挿入する // process deliver時にはキーペアが消去されているはずなので、ここで挿入する
const privateKey = await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id, 'main'); const privateKey = await this.userKeypairService.getLocalUserPrivateKeyPem(user.id, 'main');
manager.execute({ privateKey }); manager.execute({ privateKey });
} }
} }

View file

@ -10,12 +10,13 @@ import type { FollowingsRepository } from '@/models/_.js';
import type { MiLocalUser, MiRemoteUser, MiUser } from '@/models/User.js'; import type { MiLocalUser, MiRemoteUser, MiUser } from '@/models/User.js';
import { QueueService } from '@/core/QueueService.js'; import { QueueService } from '@/core/QueueService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import type { IActivity, PrivateKey } from '@/core/activitypub/type.js'; import type { IActivity } from '@/core/activitypub/type.js';
import { ThinUser } from '@/queue/types.js'; import { ThinUser } from '@/queue/types.js';
import { AccountUpdateService } from '@/core/AccountUpdateService.js'; import { AccountUpdateService } from '@/core/AccountUpdateService.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import { UserKeypairService } from '../UserKeypairService.js'; import { UserKeypairService } from '../UserKeypairService.js';
import { ApLoggerService } from './ApLoggerService.js'; import { ApLoggerService } from './ApLoggerService.js';
import type { PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures';
interface IRecipe { interface IRecipe {
type: string; type: string;
@ -128,7 +129,7 @@ class DeliverManager {
* Execute delivers * Execute delivers
*/ */
@bindThis @bindThis
public async execute(opts?: { privateKey?: PrivateKey }): Promise<void> { public async execute(opts?: { privateKey?: PrivateKeyWithPem }): Promise<void> {
//#region MIGRATION //#region MIGRATION
if (!opts?.privateKey) { if (!opts?.privateKey) {
/** /**
@ -139,7 +140,7 @@ class DeliverManager {
// createdが存在するということは新規作成されたということなので、フォロワーに配信する // createdが存在するということは新規作成されたということなので、フォロワーに配信する
this.logger.info(`ed25519 key pair created for user ${this.actor.id} and publishing to followers`); this.logger.info(`ed25519 key pair created for user ${this.actor.id} and publishing to followers`);
// リモートに配信 // リモートに配信
const keyPair = await this.userKeypairService.getLocalUserKeypairWithKeyId(created, 'main'); const keyPair = await this.userKeypairService.getLocalUserPrivateKeyPem(created, 'main');
await this.accountUpdateService.publishToFollowers(this.actor.id, keyPair); await this.accountUpdateService.publishToFollowers(this.actor.id, keyPair);
} }
} }
@ -230,7 +231,7 @@ export class ApDeliverManagerService {
* @param forceMainKey Force to use main (rsa) key * @param forceMainKey Force to use main (rsa) key
*/ */
@bindThis @bindThis
public async deliverToFollowers(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity, privateKey?: PrivateKey): Promise<void> { public async deliverToFollowers(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity, privateKey?: PrivateKeyWithPem): Promise<void> {
const manager = new DeliverManager( const manager = new DeliverManager(
this.userKeypairService, this.userKeypairService,
this.followingsRepository, this.followingsRepository,

View file

@ -22,7 +22,6 @@ import { UserKeypairService } from '@/core/UserKeypairService.js';
import { MfmService } from '@/core/MfmService.js'; import { MfmService } from '@/core/MfmService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
import type { MiUserKeypair } from '@/models/UserKeypair.js';
import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, PollsRepository } from '@/models/_.js'; import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, PollsRepository } from '@/models/_.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js';
@ -30,7 +29,8 @@ import { isNotNull } from '@/misc/is-not-null.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import { LdSignatureService } from './LdSignatureService.js'; import { LdSignatureService } from './LdSignatureService.js';
import { ApMfmService } from './ApMfmService.js'; import { ApMfmService } from './ApMfmService.js';
import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IMove, IObject, IPost, IQuestion, IReject, IRemove, ITombstone, IUndo, IUpdate, PrivateKey } from './type.js'; import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IMove, IObject, IPost, IQuestion, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js';
import type { PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures';
@Injectable() @Injectable()
export class ApRendererService { export class ApRendererService {
@ -657,10 +657,10 @@ export class ApRendererService {
} }
@bindThis @bindThis
public async attachLdSignature(activity: any, user: { id: MiUser['id']; host: null; }, key: PrivateKey): Promise<IActivity> { public async attachLdSignature(activity: any, user: { id: MiUser['id']; host: null; }, key: PrivateKeyWithPem): Promise<IActivity> {
const ldSignature = this.ldSignatureService.use(); const ldSignature = this.ldSignatureService.use();
ldSignature.debug = false; ldSignature.debug = false;
activity = await ldSignature.signRsaSignature2017(activity, key.privateKey, key.keyId); activity = await ldSignature.signRsaSignature2017(activity, key.privateKeyPem, key.keyId);
return activity; return activity;
} }

View file

@ -15,7 +15,7 @@ import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js'; import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
import type { PrivateKey } from './type.js'; import type { PrivateKeyWithPem, PrivateKey } from '@misskey-dev/node-http-message-signatures';
export async function createSignedPost(args: { level: string; key: PrivateKey; url: string; body: string; digest?: string, additionalHeaders: Record<string, string> }) { export async function createSignedPost(args: { level: string; key: PrivateKey; url: string; body: string; digest?: string, additionalHeaders: Record<string, string> }) {
const u = new URL(args.url); const u = new URL(args.url);
@ -36,7 +36,7 @@ export async function createSignedPost(args: { level: string; key: PrivateKey; u
const result = await signAsDraftToRequest( const result = await signAsDraftToRequest(
request, request,
{ keyId: args.key.keyId, privateKeyPem: args.key.privateKey }, args.key,
['(request-target)', 'date', 'host', 'digest'], ['(request-target)', 'date', 'host', 'digest'],
); );
@ -62,7 +62,7 @@ export async function createSignedGet(args: { level: string; key: PrivateKey; ur
// TODO: httpMessageSignaturesImplementationLevelによって新規格で通信をするようにする // TODO: httpMessageSignaturesImplementationLevelによって新規格で通信をするようにする
const result = await signAsDraftToRequest( const result = await signAsDraftToRequest(
request, request,
{ keyId: args.key.keyId, privateKeyPem: args.key.privateKey }, args.key,
['(request-target)', 'date', 'host', 'accept'], ['(request-target)', 'date', 'host', 'accept'],
); );
@ -89,9 +89,9 @@ export class ApRequestService {
} }
@bindThis @bindThis
public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown, level: string, digest?: string, key?: PrivateKey): Promise<void> { public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown, level: string, digest?: string, key?: PrivateKeyWithPem): Promise<void> {
const body = typeof object === 'string' ? object : JSON.stringify(object); const body = typeof object === 'string' ? object : JSON.stringify(object);
key = key ?? await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id, level); key = key ?? await this.userKeypairService.getLocalUserPrivateKeyPem(user.id, level);
const req = await createSignedPost({ const req = await createSignedPost({
level, level,
key, key,
@ -124,7 +124,7 @@ export class ApRequestService {
*/ */
@bindThis @bindThis
public async signedGet(url: string, user: { id: MiUser['id'] }, level: string): Promise<unknown> { public async signedGet(url: string, user: { id: MiUser['id'] }, level: string): Promise<unknown> {
const key = await this.userKeypairService.getLocalUserKeypairWithKeyId(user.id, level); const key = await this.userKeypairService.getLocalUserPrivateKeyPem(user.id, level);
const req = await createSignedGet({ const req = await createSignedGet({
level, level,
key, key,

View file

@ -326,8 +326,3 @@ export const isAnnounce = (object: IObject): object is IAnnounce => getApType(ob
export const isBlock = (object: IObject): object is IBlock => getApType(object) === 'Block'; export const isBlock = (object: IObject): object is IBlock => getApType(object) === 'Block';
export const isFlag = (object: IObject): object is IFlag => getApType(object) === 'Flag'; export const isFlag = (object: IObject): object is IFlag => getApType(object) === 'Flag';
export const isMove = (object: IObject): object is IMove => getApType(object) === 'Move'; export const isMove = (object: IObject): object is IMove => getApType(object) === 'Move';
export type PrivateKey = {
privateKey: string;
keyId: string;
};

View file

@ -8,8 +8,8 @@ import type { MiDriveFile } from '@/models/DriveFile.js';
import type { MiNote } from '@/models/Note.js'; import type { MiNote } from '@/models/Note.js';
import type { MiUser } from '@/models/User.js'; import type { MiUser } from '@/models/User.js';
import type { MiWebhook } from '@/models/Webhook.js'; import type { MiWebhook } from '@/models/Webhook.js';
import type { IActivity, PrivateKey } from '@/core/activitypub/type.js'; import type { IActivity } from '@/core/activitypub/type.js';
import type { ParsedSignature } from '@misskey-dev/node-http-message-signatures'; import type { ParsedSignature, PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures';
/** /**
* @peertube/http-signature * @peertube/http-signature
@ -39,7 +39,7 @@ export type DeliverJobData = {
/** whether it is sharedInbox */ /** whether it is sharedInbox */
isSharedInbox: boolean; isSharedInbox: boolean;
/** force to use main (rsa) key */ /** force to use main (rsa) key */
privateKey?: PrivateKey; privateKey?: PrivateKeyWithPem;
}; };
export type InboxJobData = { export type InboxJobData = {

View file

@ -111,8 +111,8 @@ importers:
specifier: 8.2.0 specifier: 8.2.0
version: 8.2.0 version: 8.2.0
'@misskey-dev/node-http-message-signatures': '@misskey-dev/node-http-message-signatures':
specifier: 0.0.3 specifier: 0.0.4
version: 0.0.3 version: 0.0.4
'@misskey-dev/sharp-read-bmp': '@misskey-dev/sharp-read-bmp':
specifier: 1.2.0 specifier: 1.2.0
version: 1.2.0 version: 1.2.0
@ -4754,8 +4754,8 @@ packages:
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)
dev: true dev: true
/@misskey-dev/node-http-message-signatures@0.0.3: /@misskey-dev/node-http-message-signatures@0.0.4:
resolution: {integrity: sha512-IDsdj01d0Jz/D5L4ubHGOeBLEjbIpHpGIrS7p0t2Z36ahP5cvzeawkxZW2ZuqyWQI4JendJWhGnSmDrH4N3IFg==} resolution: {integrity: sha512-hAQFaJZwJsg63JAY1RZ/yvcaxHbpZg8fLvNdJFucS270TZGunKYv7I16tuNQMKV7+BYLQNxiE7uL11KVZ9jfrg==}
engines: {node: '>=18.4.0'} engines: {node: '>=18.4.0'}
dependencies: dependencies:
'@lapo/asn1js': 1.2.4 '@lapo/asn1js': 1.2.4