fix(useragent): now using new challenge format

This commit is contained in:
Skipper
2026-04-17 18:19:39 +02:00
parent 790026e93b
commit 9ee86afc19
14 changed files with 251 additions and 47 deletions

View File

@@ -43,6 +43,14 @@ impl AuthChallenge {
buffer buffer
} }
} }
pub fn from_parts(nonce: &[u8], timestamp: i64) -> Result<Self, ()> {
let random_nonce = nonce.as_array().ok_or(())?;
Ok(AuthChallenge {
nonce: *random_nonce,
timestamp: DateTime::from_timestamp_nanos(timestamp),
})
}
} }
pub type KeyParams = MlDsa87; pub type KeyParams = MlDsa87;

View File

@@ -7,6 +7,7 @@ import 'package:arbiter/features/identity/pk_manager.dart';
import 'package:arbiter/proto/arbiter.pbgrpc.dart'; import 'package:arbiter/proto/arbiter.pbgrpc.dart';
import 'package:arbiter/proto/user_agent/auth.pb.dart' as ua_auth; import 'package:arbiter/proto/user_agent/auth.pb.dart' as ua_auth;
import 'package:arbiter/proto/user_agent.pb.dart'; import 'package:arbiter/proto/user_agent.pb.dart';
import 'package:arbiter/src/rust/api.dart';
import 'package:grpc/grpc.dart'; import 'package:grpc/grpc.dart';
import 'package:mtcore/markettakers.dart'; import 'package:mtcore/markettakers.dart';
@@ -92,7 +93,10 @@ Future<Connection> connectAndAuthorize(
); );
} }
final challenge = _formatChallenge(authResponse.challenge, pubkey); final challenge = await formatChallenge(
random: authResponse.challenge.random,
timestamp: authResponse.challenge.timestampNanos.toInt(),
);
talker.info( talker.info(
'Received auth challenge, signing with key ${base64Encode(pubkey)}', 'Received auth challenge, signing with key ${base64Encode(pubkey)}',
); );
@@ -164,9 +168,3 @@ Future<Connection> _connect(StoredServerInfo serverInfo) async {
return Connection(channel: channel, tx: tx, rx: rx); return Connection(channel: channel, tx: tx, rx: rx);
} }
List<int> _formatChallenge(ua_auth.AuthChallenge challenge, List<int> pubkey) {
final encodedPubkey = base64Encode(pubkey);
final payload = "${challenge.nonce}:$encodedPubkey";
return utf8.encode(payload);
}

View File

@@ -12,6 +12,7 @@
import 'dart:core' as $core; import 'dart:core' as $core;
import 'package:fixnum/fixnum.dart' as $fixnum;
import 'package:protobuf/protobuf.dart' as $pb; import 'package:protobuf/protobuf.dart' as $pb;
import '../shared/client.pb.dart' as $0; import '../shared/client.pb.dart' as $0;
@@ -94,12 +95,12 @@ class AuthChallengeRequest extends $pb.GeneratedMessage {
class AuthChallenge extends $pb.GeneratedMessage { class AuthChallenge extends $pb.GeneratedMessage {
factory AuthChallenge({ factory AuthChallenge({
$core.List<$core.int>? pubkey, $fixnum.Int64? timestampNanos,
$core.int? nonce, $core.List<$core.int>? random,
}) { }) {
final result = create(); final result = create();
if (pubkey != null) result.pubkey = pubkey; if (timestampNanos != null) result.timestampNanos = timestampNanos;
if (nonce != null) result.nonce = nonce; if (random != null) result.random = random;
return result; return result;
} }
@@ -117,9 +118,11 @@ class AuthChallenge extends $pb.GeneratedMessage {
package: package:
const $pb.PackageName(_omitMessageNames ? '' : 'arbiter.client.auth'), const $pb.PackageName(_omitMessageNames ? '' : 'arbiter.client.auth'),
createEmptyInstance: create) createEmptyInstance: create)
..a<$fixnum.Int64>(
1, _omitFieldNames ? '' : 'timestampNanos', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..a<$core.List<$core.int>>( ..a<$core.List<$core.int>>(
1, _omitFieldNames ? '' : 'pubkey', $pb.PbFieldType.OY) 2, _omitFieldNames ? '' : 'random', $pb.PbFieldType.OY)
..aI(2, _omitFieldNames ? '' : 'nonce')
..hasRequiredFields = false; ..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@@ -142,22 +145,22 @@ class AuthChallenge extends $pb.GeneratedMessage {
static AuthChallenge? _defaultInstance; static AuthChallenge? _defaultInstance;
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.List<$core.int> get pubkey => $_getN(0); $fixnum.Int64 get timestampNanos => $_getI64(0);
@$pb.TagNumber(1) @$pb.TagNumber(1)
set pubkey($core.List<$core.int> value) => $_setBytes(0, value); set timestampNanos($fixnum.Int64 value) => $_setInt64(0, value);
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.bool hasPubkey() => $_has(0); $core.bool hasTimestampNanos() => $_has(0);
@$pb.TagNumber(1) @$pb.TagNumber(1)
void clearPubkey() => $_clearField(1); void clearTimestampNanos() => $_clearField(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.int get nonce => $_getIZ(1); $core.List<$core.int> get random => $_getN(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
set nonce($core.int value) => $_setSignedInt32(1, value); set random($core.List<$core.int> value) => $_setBytes(1, value);
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.bool hasNonce() => $_has(1); $core.bool hasRandom() => $_has(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
void clearNonce() => $_clearField(2); void clearRandom() => $_clearField(2);
} }
class AuthChallengeSolution extends $pb.GeneratedMessage { class AuthChallengeSolution extends $pb.GeneratedMessage {

View File

@@ -62,15 +62,15 @@ final $typed_data.Uint8List authChallengeRequestDescriptor = $convert.base64Deco
const AuthChallenge$json = { const AuthChallenge$json = {
'1': 'AuthChallenge', '1': 'AuthChallenge',
'2': [ '2': [
{'1': 'pubkey', '3': 1, '4': 1, '5': 12, '10': 'pubkey'}, {'1': 'timestamp_nanos', '3': 1, '4': 1, '5': 4, '10': 'timestampNanos'},
{'1': 'nonce', '3': 2, '4': 1, '5': 5, '10': 'nonce'}, {'1': 'random', '3': 2, '4': 1, '5': 12, '10': 'random'},
], ],
}; };
/// Descriptor for `AuthChallenge`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `AuthChallenge`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List authChallengeDescriptor = $convert.base64Decode( final $typed_data.Uint8List authChallengeDescriptor = $convert.base64Decode(
'Cg1BdXRoQ2hhbGxlbmdlEhYKBnB1YmtleRgBIAEoDFIGcHVia2V5EhQKBW5vbmNlGAIgASgFUg' 'Cg1BdXRoQ2hhbGxlbmdlEicKD3RpbWVzdGFtcF9uYW5vcxgBIAEoBFIOdGltZXN0YW1wTmFub3'
'Vub25jZQ=='); 'MSFgoGcmFuZG9tGAIgASgMUgZyYW5kb20=');
@$core.Deprecated('Use authChallengeSolutionDescriptor instead') @$core.Deprecated('Use authChallengeSolutionDescriptor instead')
const AuthChallengeSolution$json = { const AuthChallengeSolution$json = {

View File

@@ -12,6 +12,7 @@
import 'dart:core' as $core; import 'dart:core' as $core;
import 'package:fixnum/fixnum.dart' as $fixnum;
import 'package:protobuf/protobuf.dart' as $pb; import 'package:protobuf/protobuf.dart' as $pb;
import 'auth.pbenum.dart'; import 'auth.pbenum.dart';
@@ -90,10 +91,12 @@ class AuthChallengeRequest extends $pb.GeneratedMessage {
class AuthChallenge extends $pb.GeneratedMessage { class AuthChallenge extends $pb.GeneratedMessage {
factory AuthChallenge({ factory AuthChallenge({
$core.int? nonce, $fixnum.Int64? timestampNanos,
$core.List<$core.int>? random,
}) { }) {
final result = create(); final result = create();
if (nonce != null) result.nonce = nonce; if (timestampNanos != null) result.timestampNanos = timestampNanos;
if (random != null) result.random = random;
return result; return result;
} }
@@ -111,7 +114,11 @@ class AuthChallenge extends $pb.GeneratedMessage {
package: const $pb.PackageName( package: const $pb.PackageName(
_omitMessageNames ? '' : 'arbiter.user_agent.auth'), _omitMessageNames ? '' : 'arbiter.user_agent.auth'),
createEmptyInstance: create) createEmptyInstance: create)
..aI(1, _omitFieldNames ? '' : 'nonce') ..a<$fixnum.Int64>(
1, _omitFieldNames ? '' : 'timestampNanos', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..a<$core.List<$core.int>>(
2, _omitFieldNames ? '' : 'random', $pb.PbFieldType.OY)
..hasRequiredFields = false; ..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@@ -134,13 +141,22 @@ class AuthChallenge extends $pb.GeneratedMessage {
static AuthChallenge? _defaultInstance; static AuthChallenge? _defaultInstance;
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.int get nonce => $_getIZ(0); $fixnum.Int64 get timestampNanos => $_getI64(0);
@$pb.TagNumber(1) @$pb.TagNumber(1)
set nonce($core.int value) => $_setSignedInt32(0, value); set timestampNanos($fixnum.Int64 value) => $_setInt64(0, value);
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.bool hasNonce() => $_has(0); $core.bool hasTimestampNanos() => $_has(0);
@$pb.TagNumber(1) @$pb.TagNumber(1)
void clearNonce() => $_clearField(1); void clearTimestampNanos() => $_clearField(1);
@$pb.TagNumber(2)
$core.List<$core.int> get random => $_getN(1);
@$pb.TagNumber(2)
set random($core.List<$core.int> value) => $_setBytes(1, value);
@$pb.TagNumber(2)
$core.bool hasRandom() => $_has(1);
@$pb.TagNumber(2)
void clearRandom() => $_clearField(2);
} }
class AuthChallengeSolution extends $pb.GeneratedMessage { class AuthChallengeSolution extends $pb.GeneratedMessage {

View File

@@ -67,13 +67,15 @@ final $typed_data.Uint8List authChallengeRequestDescriptor = $convert.base64Deco
const AuthChallenge$json = { const AuthChallenge$json = {
'1': 'AuthChallenge', '1': 'AuthChallenge',
'2': [ '2': [
{'1': 'nonce', '3': 1, '4': 1, '5': 5, '10': 'nonce'}, {'1': 'timestamp_nanos', '3': 1, '4': 1, '5': 4, '10': 'timestampNanos'},
{'1': 'random', '3': 2, '4': 1, '5': 12, '10': 'random'},
], ],
}; };
/// Descriptor for `AuthChallenge`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `AuthChallenge`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List authChallengeDescriptor = $convert final $typed_data.Uint8List authChallengeDescriptor = $convert.base64Decode(
.base64Decode('Cg1BdXRoQ2hhbGxlbmdlEhQKBW5vbmNlGAEgASgFUgVub25jZQ=='); 'Cg1BdXRoQ2hhbGxlbmdlEicKD3RpbWVzdGFtcF9uYW5vcxgBIAEoBFIOdGltZXN0YW1wTmFub3'
'MSFgoGcmFuZG9tGAIgASgMUgZyYW5kb20=');
@$core.Deprecated('Use authChallengeSolutionDescriptor instead') @$core.Deprecated('Use authChallengeSolutionDescriptor instead')
const AuthChallengeSolution$json = { const AuthChallengeSolution$json = {

View File

@@ -6,6 +6,14 @@
import 'frb_generated.dart'; import 'frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
Future<Uint8List> formatChallenge({
required List<int> random,
required PlatformInt64 timestamp,
}) => RustLib.instance.api.crateApiFormatChallenge(
random: random,
timestamp: timestamp,
);
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>> // Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<MldsaKey>>
abstract class MldsaKey implements RustOpaqueInterface { abstract class MldsaKey implements RustOpaqueInterface {
static Future<MldsaKey> fromBytes({required List<int> bytes}) => static Future<MldsaKey> fromBytes({required List<int> bytes}) =>

View File

@@ -64,7 +64,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
String get codegenVersion => '2.12.0'; String get codegenVersion => '2.12.0';
@override @override
int get rustContentHash => -437661335; int get rustContentHash => 1247923898;
static const kDefaultExternalLibraryLoaderConfig = static const kDefaultExternalLibraryLoaderConfig =
ExternalLibraryLoaderConfig( ExternalLibraryLoaderConfig(
@@ -89,6 +89,11 @@ abstract class RustLibApi extends BaseApi {
Future<Uint8List> crateApiMldsaKeyToBytes({required MldsaKey that}); Future<Uint8List> crateApiMldsaKeyToBytes({required MldsaKey that});
Future<Uint8List> crateApiFormatChallenge({
required List<int> random,
required PlatformInt64 timestamp,
});
RustArcIncrementStrongCountFnType RustArcIncrementStrongCountFnType
get rust_arc_increment_strong_count_MldsaKey; get rust_arc_increment_strong_count_MldsaKey;
@@ -267,6 +272,40 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
TaskConstMeta get kCrateApiMldsaKeyToBytesConstMeta => TaskConstMeta get kCrateApiMldsaKeyToBytesConstMeta =>
const TaskConstMeta(debugName: "MldsaKey_to_bytes", argNames: ["that"]); const TaskConstMeta(debugName: "MldsaKey_to_bytes", argNames: ["that"]);
@override
Future<Uint8List> crateApiFormatChallenge({
required List<int> random,
required PlatformInt64 timestamp,
}) {
return handler.executeNormal(
NormalTask(
callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_list_prim_u_8_loose(random, serializer);
sse_encode_i_64(timestamp, serializer);
pdeCallFfi(
generalizedFrbRustBinding,
serializer,
funcId: 6,
port: port_,
);
},
codec: SseCodec(
decodeSuccessData: sse_decode_list_prim_u_8_strict,
decodeErrorData: sse_decode_String,
),
constMeta: kCrateApiFormatChallengeConstMeta,
argValues: [random, timestamp],
apiImpl: this,
),
);
}
TaskConstMeta get kCrateApiFormatChallengeConstMeta => const TaskConstMeta(
debugName: "format_challenge",
argNames: ["random", "timestamp"],
);
RustArcIncrementStrongCountFnType RustArcIncrementStrongCountFnType
get rust_arc_increment_strong_count_MldsaKey => wire get rust_arc_increment_strong_count_MldsaKey => wire
.rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey; .rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey;
@@ -314,6 +353,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return raw as String; return raw as String;
} }
@protected
PlatformInt64 dco_decode_i_64(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
return dcoDecodeI64(raw);
}
@protected @protected
List<int> dco_decode_list_prim_u_8_loose(dynamic raw) { List<int> dco_decode_list_prim_u_8_loose(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs // Codec=Dco (DartCObject based), see doc to use other codecs
@@ -394,6 +439,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return utf8.decoder.convert(inner); return utf8.decoder.convert(inner);
} }
@protected
PlatformInt64 sse_decode_i_64(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
return deserializer.buffer.getPlatformInt64();
}
@protected @protected
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer) { List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
@@ -491,6 +542,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer); sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer);
} }
@protected
void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
serializer.buffer.putPlatformInt64(self);
}
@protected @protected
void sse_encode_list_prim_u_8_loose( void sse_encode_list_prim_u_8_loose(
List<int> self, List<int> self,

View File

@@ -46,6 +46,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
String dco_decode_String(dynamic raw); String dco_decode_String(dynamic raw);
@protected
PlatformInt64 dco_decode_i_64(dynamic raw);
@protected @protected
List<int> dco_decode_list_prim_u_8_loose(dynamic raw); List<int> dco_decode_list_prim_u_8_loose(dynamic raw);
@@ -85,6 +88,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
String sse_decode_String(SseDeserializer deserializer); String sse_decode_String(SseDeserializer deserializer);
@protected
PlatformInt64 sse_decode_i_64(SseDeserializer deserializer);
@protected @protected
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer); List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer);
@@ -136,6 +142,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
void sse_encode_String(String self, SseSerializer serializer); void sse_encode_String(String self, SseSerializer serializer);
@protected
void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer);
@protected @protected
void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer); void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer);

View File

@@ -48,6 +48,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
String dco_decode_String(dynamic raw); String dco_decode_String(dynamic raw);
@protected
PlatformInt64 dco_decode_i_64(dynamic raw);
@protected @protected
List<int> dco_decode_list_prim_u_8_loose(dynamic raw); List<int> dco_decode_list_prim_u_8_loose(dynamic raw);
@@ -87,6 +90,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
String sse_decode_String(SseDeserializer deserializer); String sse_decode_String(SseDeserializer deserializer);
@protected
PlatformInt64 sse_decode_i_64(SseDeserializer deserializer);
@protected @protected
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer); List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer);
@@ -138,6 +144,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
void sse_encode_String(String self, SseSerializer serializer); void sse_encode_String(String self, SseSerializer serializer);
@protected
void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer);
@protected @protected
void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer); void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer);

4
useragent/mise.toml Normal file
View File

@@ -0,0 +1,4 @@
[tasks.codegen]
run = '''
flutter_rust_bridge_codegen generate
'''

View File

@@ -232,7 +232,7 @@ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
name = "arbiter-crypto" name = "arbiter-crypto"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"base64", "chrono",
"memsafe", "memsafe",
"ml-dsa", "ml-dsa",
"rand", "rand",
@@ -487,12 +487,6 @@ dependencies = [
"rustc-demangle", "rustc-demangle",
] ]
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
version = "1.8.3" version = "1.8.3"
@@ -718,6 +712,20 @@ dependencies = [
"rand_core", "rand_core",
] ]
[[package]]
name = "chrono"
version = "0.4.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-link",
]
[[package]] [[package]]
name = "clipboard-win" name = "clipboard-win"
version = "5.4.1" version = "5.4.1"
@@ -1821,6 +1829,30 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "iana-time-zone"
version = "0.1.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "icu_collections" name = "icu_collections"
version = "2.2.0" version = "2.2.0"

View File

@@ -1,13 +1,15 @@
use anyhow::anyhow; use anyhow::anyhow;
use arbiter_crypto::authn::{self, AuthChallenge, USERAGENT_CONTEXT};
use flutter_rust_bridge::frb; use flutter_rust_bridge::frb;
use arbiter_crypto::authn::{self, USERAGENT_CONTEXT};
#[frb(opaque)] #[frb(opaque)]
pub struct MldsaKey(authn::SigningKey); pub struct MldsaKey(authn::SigningKey);
impl MldsaKey { impl MldsaKey {
pub fn from_bytes(bytes: &[u8]) -> anyhow::Result<Self> { pub fn from_bytes(bytes: &[u8]) -> anyhow::Result<Self> {
let bytes: [u8; 32] = bytes.try_into().map_err(|_| anyhow!("Invalid key length"))?; let bytes: [u8; 32] = bytes
.try_into()
.map_err(|_| anyhow!("Invalid key length"))?;
Ok(Self(authn::SigningKey::from_seed(bytes))) Ok(Self(authn::SigningKey::from_seed(bytes)))
} }
@@ -27,3 +29,10 @@ impl MldsaKey {
self.0.public_key().to_bytes().to_vec() self.0.public_key().to_bytes().to_vec()
} }
} }
pub fn format_challenge(random: Vec<u8>, timestamp: i64) -> Result<Vec<u8>, String> {
let challenge = AuthChallenge::from_parts(&random, timestamp)
.map_err(|_| "Invalid nonce length".to_string())?;
Ok(challenge.format())
}

View File

@@ -39,7 +39,7 @@ flutter_rust_bridge::frb_generated_boilerplate!(
default_rust_auto_opaque = RustAutoOpaqueMoi, default_rust_auto_opaque = RustAutoOpaqueMoi,
); );
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0"; pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0";
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -437661335; pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1247923898;
// Section: executor // Section: executor
@@ -267,6 +267,40 @@ fn wire__crate__api__MldsaKey_to_bytes_impl(
}, },
) )
} }
fn wire__crate__api__format_challenge_impl(
port_: flutter_rust_bridge::for_generated::MessagePort,
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
rust_vec_len_: i32,
data_len_: i32,
) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(
flutter_rust_bridge::for_generated::TaskInfo {
debug_name: "format_challenge",
port: Some(port_),
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
},
move || {
let message = unsafe {
flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
ptr_,
rust_vec_len_,
data_len_,
)
};
let mut deserializer =
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
let api_random = <Vec<u8>>::sse_decode(&mut deserializer);
let api_timestamp = <i64>::sse_decode(&mut deserializer);
deserializer.end();
move |context| {
transform_result_sse::<_, String>((move || {
let output_ok = crate::api::format_challenge(api_random, api_timestamp)?;
Ok(output_ok)
})())
}
},
)
}
// Section: related_funcs // Section: related_funcs
@@ -312,6 +346,13 @@ impl SseDecode for String {
} }
} }
impl SseDecode for i64 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
deserializer.cursor.read_i64::<NativeEndian>().unwrap()
}
}
impl SseDecode for Vec<u8> { impl SseDecode for Vec<u8> {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
@@ -371,6 +412,7 @@ fn pde_ffi_dispatcher_primary_impl(
3 => wire__crate__api__MldsaKey_get_public_key_impl(port, ptr, rust_vec_len, data_len), 3 => wire__crate__api__MldsaKey_get_public_key_impl(port, ptr, rust_vec_len, data_len),
4 => wire__crate__api__MldsaKey_sign_impl(port, ptr, rust_vec_len, data_len), 4 => wire__crate__api__MldsaKey_sign_impl(port, ptr, rust_vec_len, data_len),
5 => wire__crate__api__MldsaKey_to_bytes_impl(port, ptr, rust_vec_len, data_len), 5 => wire__crate__api__MldsaKey_to_bytes_impl(port, ptr, rust_vec_len, data_len),
6 => wire__crate__api__format_challenge_impl(port, ptr, rust_vec_len, data_len),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -436,6 +478,13 @@ impl SseEncode for String {
} }
} }
impl SseEncode for i64 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
serializer.cursor.write_i64::<NativeEndian>(self).unwrap();
}
}
impl SseEncode for Vec<u8> { impl SseEncode for Vec<u8> {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {