import 'dart:convert'; import 'dart:typed_data'; import 'package:dio/dio.dart'; import '../../../common/network/dio_provider.dart'; /// Compatible with Yanting's protobuf `/api/v1/auth/onekey/verify` contract. class OneKeyLoginApi { OneKeyLoginApi(this._dio); final Dio _dio; Future verify(String loginToken) async { final bytes = utf8.encode(loginToken); final request = Uint8List.fromList([ 0x0A, ..._varint(bytes.length), ...bytes, ]); final response = await _dio.post>( '/api/v1/auth/onekey/verify', data: request, options: protobufOptions(), ); return _decode(Uint8List.fromList(response.data ?? const [])); } OneKeyLoginReply _decode(Uint8List data) { final fields = _fields(data); final token = utf8.decode(fields[1] ?? const []); final user = _fields(Uint8List.fromList(fields[3] ?? const [])); if (token.isEmpty) throw StateError('一键登录服务未返回登录凭证'); return OneKeyLoginReply( token: token, phone: utf8.decode(user[2] ?? const []), ); } Map> _fields(Uint8List data) { final result = >{}; var i = 0; while (i < data.length) { final tag = _readVarint(data, i); i = tag.$2; final wireType = tag.$1 & 7; if (wireType == 0) { i = _readVarint(data, i).$2; continue; } if (wireType != 2) { throw const FormatException('Unsupported protobuf field'); } final length = _readVarint(data, i); i = length.$2; final end = i + length.$1; if (end > data.length) { throw const FormatException('Invalid protobuf payload'); } result[tag.$1 >> 3] = data.sublist(i, end); i = end; } return result; } (int, int) _readVarint(Uint8List data, int index) { var value = 0; var shift = 0; while (index < data.length) { final byte = data[index++]; value |= (byte & 0x7f) << shift; if (byte & 0x80 == 0) return (value, index); shift += 7; } throw const FormatException('Invalid protobuf varint'); } List _varint(int value) { final result = []; while (value > 0x7f) { result.add((value & 0x7f) | 0x80); value >>= 7; } result.add(value); return result; } } class OneKeyLoginReply { const OneKeyLoginReply({required this.token, required this.phone}); final String token; final String phone; }