102 lines
3.1 KiB
TypeScript
102 lines
3.1 KiB
TypeScript
import { createHash } from 'crypto';
|
|
import { Injectable } from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { Repository } from 'typeorm';
|
|
import { ensureSnowflakeId } from '@/common';
|
|
import { NapcatDeviceIdentity } from './napcat-device-identity.entity';
|
|
|
|
type ResolveNapcatDeviceIdentityInput = {
|
|
accountId: string;
|
|
containerId?: string;
|
|
selfId?: string;
|
|
};
|
|
|
|
@Injectable()
|
|
export class NapcatDeviceIdentityService {
|
|
constructor(
|
|
@InjectRepository(NapcatDeviceIdentity)
|
|
private readonly identityRepository: Repository<NapcatDeviceIdentity>,
|
|
private readonly configService: ConfigService,
|
|
) {}
|
|
|
|
async resolveForAccount(input: ResolveNapcatDeviceIdentityInput) {
|
|
const accountId = `${input.accountId}`.trim();
|
|
const existing = await this.identityRepository.findOne({
|
|
where: { accountId },
|
|
});
|
|
|
|
if (existing) {
|
|
const containerId = input.containerId || null;
|
|
if (containerId && existing.containerId !== containerId) {
|
|
await this.identityRepository.update(
|
|
{ id: existing.id },
|
|
{ containerId },
|
|
);
|
|
existing.containerId = containerId;
|
|
}
|
|
return existing;
|
|
}
|
|
|
|
const containerName = this.buildContainerName(input.selfId || accountId);
|
|
const dataDir = `${this.getRootDir()}/${containerName}`;
|
|
const identity = this.identityRepository.create({
|
|
accountId,
|
|
containerId: input.containerId || null,
|
|
dataDir,
|
|
hostname: this.buildHostname(containerName),
|
|
lastLoginEvidence: null,
|
|
macAddress: this.buildMacAddress(accountId, containerName),
|
|
machineIdPath: `${dataDir}/machine-id`,
|
|
verificationStatus: 'pending',
|
|
});
|
|
ensureSnowflakeId(identity);
|
|
|
|
return this.identityRepository.save(identity);
|
|
}
|
|
|
|
private buildContainerName(seed: string) {
|
|
const prefix = this.getConfig(
|
|
'QQBOT_NAPCAT_CONTAINER_PREFIX',
|
|
'kt-qqbot-napcat',
|
|
);
|
|
const suffix = `${seed || 'unknown'}`
|
|
.replace(/[^a-zA-Z0-9_.-]/g, '-')
|
|
.toLowerCase();
|
|
return `${prefix}-${suffix}`.replace(/-+/g, '-').slice(0, 120);
|
|
}
|
|
|
|
private buildHostname(containerName: string) {
|
|
const normalized = containerName
|
|
.replace(/[^a-zA-Z0-9-]/g, '-')
|
|
.replace(/-+/g, '-')
|
|
.replace(/^-|-$/g, '');
|
|
if (normalized.length <= 63) return normalized;
|
|
|
|
const hash = createHash('sha256').update(containerName).digest('hex');
|
|
return `${normalized.slice(0, 50)}-${hash.slice(0, 12)}`.slice(0, 63);
|
|
}
|
|
|
|
private buildMacAddress(accountId: string, containerName: string) {
|
|
const hash = createHash('sha256')
|
|
.update(`${accountId}:${containerName}`)
|
|
.digest('hex');
|
|
return ['02', '42', hash.slice(0, 2), hash.slice(2, 4), hash.slice(4, 6), hash.slice(6, 8)].join(
|
|
':',
|
|
);
|
|
}
|
|
|
|
private getRootDir() {
|
|
return (
|
|
this.getConfig(
|
|
'QQBOT_NAPCAT_ROOT',
|
|
'/vol1/docker/kt-qqbot/napcat-instances',
|
|
)
|
|
).replace(/[\\/]+$/, '');
|
|
}
|
|
|
|
private getConfig(key: string, defaultValue = '') {
|
|
return `${this.configService.get<string>(key) || defaultValue}`.trim();
|
|
}
|
|
}
|