mirror of
https://github.com/certd/certd.git
synced 2026-07-06 20:37:34 +08:00
134 lines
3.7 KiB
TypeScript
134 lines
3.7 KiB
TypeScript
import { logger } from "@certd/basic";
|
|
import { AccessService } from "@certd/lib-server";
|
|
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
|
import { Like } from "typeorm";
|
|
import { StorageService } from "../../pipeline/service/storage-service.js";
|
|
import { parseStorageValue } from "./google-common-eab-account-key-fix.js";
|
|
|
|
export type LegacyAcmeAccountConfig = {
|
|
key?: string;
|
|
privateKey?: string;
|
|
accountKey?: string;
|
|
accountUrl?: string;
|
|
accountUri?: string;
|
|
};
|
|
|
|
export function parseLegacyAcmeStorageKey(key: string) {
|
|
const match = /^acme\.config\.([^.]+)\.(.+)$/.exec(key);
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
if (match[2].startsWith("access.")) {
|
|
return null;
|
|
}
|
|
return {
|
|
caType: match[1],
|
|
email: match[2],
|
|
};
|
|
}
|
|
|
|
export function buildAcmeAccountSetting(req: { caType: string; email: string; config: LegacyAcmeAccountConfig }) {
|
|
const accountKey = req.config.privateKey || req.config.key || req.config.accountKey;
|
|
const accountUri = req.config.accountUri || req.config.accountUrl;
|
|
if (!accountKey || !accountUri) {
|
|
return null;
|
|
}
|
|
return {
|
|
caType: req.caType,
|
|
email: req.email,
|
|
account: JSON.stringify({
|
|
accountKey,
|
|
accountUri,
|
|
caType: req.caType,
|
|
email: req.email,
|
|
directoryUrl: "",
|
|
migratedFrom: "legacy-storage",
|
|
}),
|
|
};
|
|
}
|
|
|
|
export function maskAcmeAccountEmail(email: string) {
|
|
if (!email) {
|
|
return "unknown";
|
|
}
|
|
const atIndex = email.indexOf("@");
|
|
if (atIndex < 0) {
|
|
return email.length <= 2 ? `${email[0] || ""}*******` : `${email.substring(0, 2)}*******`;
|
|
}
|
|
const name = email.substring(0, atIndex);
|
|
const domain = email.substring(atIndex + 1);
|
|
const prefix = name.substring(0, Math.min(2, name.length));
|
|
return `${prefix}*******${domain}`;
|
|
}
|
|
|
|
export function buildAcmeAccountAccessName(caType: string, email: string) {
|
|
return `${caType}-acme-${maskAcmeAccountEmail(email)}`;
|
|
}
|
|
|
|
@Provide()
|
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
|
export class LegacyAcmeAccountAccessFix {
|
|
@Inject()
|
|
storageService: StorageService;
|
|
|
|
@Inject()
|
|
accessService: AccessService;
|
|
|
|
async init() {
|
|
try {
|
|
const repository = this.storageService.getRepository();
|
|
const records = await repository.find({
|
|
where: {
|
|
scope: "user",
|
|
key: Like("acme.config.%"),
|
|
},
|
|
});
|
|
let count = 0;
|
|
for (const record of records) {
|
|
const parsedKey = parseLegacyAcmeStorageKey(record.key);
|
|
if (!parsedKey) {
|
|
continue;
|
|
}
|
|
const config = parseStorageValue(record.value) as LegacyAcmeAccountConfig;
|
|
const setting = buildAcmeAccountSetting({
|
|
...parsedKey,
|
|
config,
|
|
});
|
|
if (!setting) {
|
|
continue;
|
|
}
|
|
const name = buildAcmeAccountAccessName(parsedKey.caType, parsedKey.email);
|
|
const query = {
|
|
userId: record.userId,
|
|
type: "acmeAccount",
|
|
subtype: parsedKey.caType,
|
|
name,
|
|
} as any;
|
|
if (record.projectId) {
|
|
query.projectId = record.projectId;
|
|
}
|
|
const exists = await this.accessService.findOne({
|
|
where: query,
|
|
});
|
|
if (exists) {
|
|
continue;
|
|
}
|
|
await this.accessService.add({
|
|
userId: record.userId,
|
|
projectId: record.projectId,
|
|
type: "acmeAccount",
|
|
subtype: parsedKey.caType,
|
|
name,
|
|
setting: JSON.stringify(setting),
|
|
});
|
|
count++;
|
|
}
|
|
logger.info(`旧ACME账号迁移完成,生成${count}个ACME账号授权`);
|
|
return true;
|
|
} catch (e: any) {
|
|
logger.error("旧ACME账号迁移失败", e);
|
|
return false;
|
|
}
|
|
}
|
|
}
|