refactor: improve auto-create API semantics and use real device ID
Frontend (account_service.dart): - Use Android ID instead of random UUID for deviceId - Add DeviceHardwareInfo class with full hardware details - Remove provinceCode/cityCode from CreateAccountRequest - Simplify to: deviceId (required), deviceName (optional JSON), inviterReferralCode (optional) Backend (identity-service): - Rename validateDeviceId() to checkDeviceNotRegistered() for clarity - Rename generateNext() to generateNextUserSequence() for semantics - Update error message: "该设备已创建过账户" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
bc82f58549
commit
17fd663fe3
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(cat:*)",
|
||||
"Bash(git add:*)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(git push:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
|
|
@ -26,8 +26,8 @@ export class AutoCreateAccountHandler {
|
|||
) {}
|
||||
|
||||
async execute(command: AutoCreateAccountCommand): Promise<AutoCreateAccountResult> {
|
||||
const deviceValidation = await this.validatorService.validateDeviceId(command.deviceId);
|
||||
if (!deviceValidation.isValid) throw new ApplicationError(deviceValidation.errorMessage!);
|
||||
const deviceCheck = await this.validatorService.checkDeviceNotRegistered(command.deviceId);
|
||||
if (!deviceCheck.isValid) throw new ApplicationError(deviceCheck.errorMessage!);
|
||||
|
||||
let inviterSequence: AccountSequence | null = null;
|
||||
if (command.inviterReferralCode) {
|
||||
|
|
@ -38,7 +38,7 @@ export class AutoCreateAccountHandler {
|
|||
inviterSequence = inviter!.accountSequence;
|
||||
}
|
||||
|
||||
const accountSequence = await this.sequenceGenerator.generateNext();
|
||||
const accountSequence = await this.sequenceGenerator.generateNextUserSequence();
|
||||
|
||||
const account = UserAccount.createAutomatic({
|
||||
accountSequence,
|
||||
|
|
|
|||
|
|
@ -73,8 +73,8 @@ export class UserApplicationService {
|
|||
inviterSequence = inviter!.accountSequence;
|
||||
}
|
||||
|
||||
// 3. 生成账户序列号
|
||||
const accountSequence = await this.sequenceGenerator.generateNext();
|
||||
// 3. 生成用户序列号
|
||||
const accountSequence = await this.sequenceGenerator.generateNextUserSequence();
|
||||
|
||||
// 4. 创建用户账户
|
||||
const account = UserAccount.createAutomatic({
|
||||
|
|
@ -301,7 +301,7 @@ export class UserApplicationService {
|
|||
inviterSequence = inviter!.accountSequence;
|
||||
}
|
||||
|
||||
const accountSequence = await this.sequenceGenerator.generateNext();
|
||||
const accountSequence = await this.sequenceGenerator.generateNextUserSequence();
|
||||
|
||||
const account = UserAccount.create({
|
||||
accountSequence,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export class AccountSequenceGeneratorService {
|
|||
private readonly repository: UserAccountRepository,
|
||||
) {}
|
||||
|
||||
async generateNext(): Promise<AccountSequence> {
|
||||
async generateNextUserSequence(): Promise<AccountSequence> {
|
||||
return this.repository.getNextAccountSequence();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ export class UserValidatorService {
|
|||
return ValidationResult.success();
|
||||
}
|
||||
|
||||
async validateDeviceId(deviceId: string): Promise<ValidationResult> {
|
||||
async checkDeviceNotRegistered(deviceId: string): Promise<ValidationResult> {
|
||||
const existing = await this.repository.findByDeviceId(deviceId);
|
||||
if (existing) return ValidationResult.failure('该设备已创建账户');
|
||||
if (existing) return ValidationResult.failure('该设备已创建过账户');
|
||||
return ValidationResult.success();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,29 +8,60 @@ import '../storage/storage_keys.dart';
|
|||
import '../errors/exceptions.dart';
|
||||
import 'mpc_share_service.dart';
|
||||
|
||||
/// 设备硬件信息 (存储在 deviceName 字段中)
|
||||
class DeviceHardwareInfo {
|
||||
final String? brand; // 品牌 (如 "Xiaomi")
|
||||
final String? manufacturer; // 厂商 (如 "Xiaomi")
|
||||
final String? model; // 型号 (如 "Mi 11")
|
||||
final String? device; // 设备名 (如 "venus")
|
||||
final String? product; // 产品名 (如 "venus_eea")
|
||||
final String? hardware; // 硬件名 (如 "qcom")
|
||||
final String? osVersion; // 系统版本 (如 "13")
|
||||
final int? sdkInt; // SDK 版本 (如 33)
|
||||
final bool? isPhysicalDevice; // 是否真机
|
||||
|
||||
DeviceHardwareInfo({
|
||||
this.brand,
|
||||
this.manufacturer,
|
||||
this.model,
|
||||
this.device,
|
||||
this.product,
|
||||
this.hardware,
|
||||
this.osVersion,
|
||||
this.sdkInt,
|
||||
this.isPhysicalDevice,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
if (brand != null) 'brand': brand,
|
||||
if (manufacturer != null) 'manufacturer': manufacturer,
|
||||
if (model != null) 'model': model,
|
||||
if (device != null) 'device': device,
|
||||
if (product != null) 'product': product,
|
||||
if (hardware != null) 'hardware': hardware,
|
||||
if (osVersion != null) 'osVersion': osVersion,
|
||||
if (sdkInt != null) 'sdkInt': sdkInt,
|
||||
if (isPhysicalDevice != null) 'isPhysicalDevice': isPhysicalDevice,
|
||||
};
|
||||
}
|
||||
|
||||
/// 创建账号请求
|
||||
class CreateAccountRequest {
|
||||
final String deviceId;
|
||||
final String? deviceName;
|
||||
final String? inviterReferralCode;
|
||||
final String? provinceCode;
|
||||
final String? cityCode;
|
||||
final String deviceId; // 必填: Android ID 或 iOS identifierForVendor
|
||||
final DeviceHardwareInfo? deviceName; // 可选: 设备硬件信息 (JSON)
|
||||
final String? inviterReferralCode; // 可选: 邀请人推荐码
|
||||
|
||||
CreateAccountRequest({
|
||||
required this.deviceId,
|
||||
this.deviceName,
|
||||
this.inviterReferralCode,
|
||||
this.provinceCode,
|
||||
this.cityCode,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'deviceId': deviceId,
|
||||
if (deviceName != null) 'deviceName': deviceName,
|
||||
if (deviceName != null) 'deviceName': deviceName!.toJson(),
|
||||
if (inviterReferralCode != null)
|
||||
'inviterReferralCode': inviterReferralCode,
|
||||
if (provinceCode != null) 'provinceCode': provinceCode,
|
||||
if (cityCode != null) 'cityCode': cityCode,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -108,33 +139,59 @@ class AccountService {
|
|||
}) : _apiClient = apiClient,
|
||||
_secureStorage = secureStorage;
|
||||
|
||||
/// 获取或生成设备ID
|
||||
Future<String> getOrCreateDeviceId() async {
|
||||
// 尝试从存储读取
|
||||
var deviceId = await _secureStorage.read(key: StorageKeys.deviceId);
|
||||
if (deviceId != null && deviceId.isNotEmpty) {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
// 生成新的设备ID
|
||||
deviceId = const Uuid().v4();
|
||||
await _secureStorage.write(key: StorageKeys.deviceId, value: deviceId);
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
/// 获取设备名称
|
||||
Future<String> getDeviceName() async {
|
||||
final deviceInfo = DeviceInfoPlugin();
|
||||
/// 获取设备唯一标识符
|
||||
///
|
||||
/// Android: 使用 Android ID (64位十六进制字符串)
|
||||
/// iOS: 使用 identifierForVendor
|
||||
Future<String> getDeviceId() async {
|
||||
final deviceInfoPlugin = DeviceInfoPlugin();
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
final info = await deviceInfo.androidInfo;
|
||||
return '${info.brand} ${info.model}';
|
||||
final info = await deviceInfoPlugin.androidInfo;
|
||||
return info.id; // Android ID
|
||||
} else if (Platform.isIOS) {
|
||||
final info = await deviceInfo.iosInfo;
|
||||
return info.name;
|
||||
final info = await deviceInfoPlugin.iosInfo;
|
||||
return info.identifierForVendor ?? const Uuid().v4();
|
||||
}
|
||||
|
||||
return 'Unknown Device';
|
||||
// 其他平台回退到 UUID
|
||||
return const Uuid().v4();
|
||||
}
|
||||
|
||||
/// 获取设备硬件信息
|
||||
///
|
||||
/// Android: 完整硬件信息
|
||||
/// iOS: 基本信息
|
||||
Future<DeviceHardwareInfo> getDeviceHardwareInfo() async {
|
||||
final deviceInfoPlugin = DeviceInfoPlugin();
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
final info = await deviceInfoPlugin.androidInfo;
|
||||
return DeviceHardwareInfo(
|
||||
brand: info.brand,
|
||||
manufacturer: info.manufacturer,
|
||||
model: info.model,
|
||||
device: info.device,
|
||||
product: info.product,
|
||||
hardware: info.hardware,
|
||||
osVersion: info.version.release,
|
||||
sdkInt: info.version.sdkInt,
|
||||
isPhysicalDevice: info.isPhysicalDevice,
|
||||
);
|
||||
} else if (Platform.isIOS) {
|
||||
final info = await deviceInfoPlugin.iosInfo;
|
||||
return DeviceHardwareInfo(
|
||||
brand: 'Apple',
|
||||
manufacturer: 'Apple',
|
||||
model: info.model,
|
||||
device: info.name,
|
||||
osVersion: info.systemVersion,
|
||||
isPhysicalDevice: info.isPhysicalDevice,
|
||||
);
|
||||
}
|
||||
|
||||
// 其他平台返回空信息
|
||||
return DeviceHardwareInfo();
|
||||
}
|
||||
|
||||
/// 自动创建账号 (首次打开APP)
|
||||
|
|
@ -142,13 +199,12 @@ class AccountService {
|
|||
/// 使用 MPC 2-of-3 协议生成钱包地址
|
||||
Future<CreateAccountResponse> createAccount({
|
||||
String? inviterReferralCode,
|
||||
String? provinceCode,
|
||||
String? cityCode,
|
||||
}) async {
|
||||
try {
|
||||
// 获取设备信息
|
||||
final deviceId = await getOrCreateDeviceId();
|
||||
final deviceName = await getDeviceName();
|
||||
// 获取设备ID (必填)
|
||||
final deviceId = await getDeviceId();
|
||||
// 获取设备硬件信息 (可选)
|
||||
final deviceName = await getDeviceHardwareInfo();
|
||||
|
||||
// 调用 API
|
||||
final response = await _apiClient.post(
|
||||
|
|
@ -157,8 +213,6 @@ class AccountService {
|
|||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
inviterReferralCode: inviterReferralCode,
|
||||
provinceCode: provinceCode,
|
||||
cityCode: cityCode,
|
||||
).toJson(),
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue