fix(mobile): let the issuer choose relay assertion lifetime

Mobile rejected any NIP-FI relay assertion expiring more than 300s out,
so once the issuer moves to longer lifetimes, org sign-in fails on every
fetch and the Block relay can't connect. Keep the expired check and drop
the cap, matching desktop (block/buzz-app#2171). The token cache already
refreshes from expires_at.

Co-authored-by: claude00 <fb8b76a01257932b8ca35060862c29bd09b2137638573731c2d5074fc02c5385@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
This commit is contained in:
Bradley Axen
2026-11-02 10:15:39 -08:00
parent da93ce3f62
commit f2024a5ac5
2 changed files with 29 additions and 2 deletions

View File

@@ -223,7 +223,7 @@ class HostedRelayAuth extends ChangeNotifier {
throw AccountFailure.invalidResponse;
}
final now = _now().millisecondsSinceEpoch ~/ 1000;
if (expiry <= now || expiry > now + 300) {
if (expiry <= now) {
throw AccountFailure.invalidResponse;
}
final expires = DateTime.fromMillisecondsSinceEpoch(

View File

@@ -87,6 +87,7 @@ void main() {
group('organization relay assertions', () {
late List<http.Request> requests;
late Object? boundIdentity;
late int assertionLifetime;
BuilderlabAccountClient organizationClient() => BuilderlabAccountClient(
accountOrigin: organization,
@@ -110,7 +111,9 @@ void main() {
jsonEncode({
'assertion': 'org-token',
'nostr_pubkey': keys.public,
'expires_at': DateTime.now().millisecondsSinceEpoch ~/ 1000 + 120,
'expires_at':
DateTime.now().millisecondsSinceEpoch ~/ 1000 +
assertionLifetime,
}),
200,
),
@@ -145,6 +148,7 @@ void main() {
setUp(() {
requests = [];
boundIdentity = null;
assertionLifetime = 120;
});
test(
@@ -173,6 +177,29 @@ void main() {
},
);
test('the issuer chooses the lifetime of an unexpired assertion', () async {
await saveSession();
for (final (lifetime, accepted) in [
(300, true),
(86400, true),
(0, false),
(-60, false),
]) {
assertionLifetime = lifetime;
final auth = relayAuth(organizationClient());
if (accepted) {
expect(await auth.headers(relay), {
'Nostr-Federated-Identity': 'Bearer org-token',
});
} else {
await expectLater(
auth.headers(relay),
throwsA(AccountFailure.invalidResponse),
);
}
}
});
test('a key bound to the same member is accepted', () async {
await saveSession();
boundIdentity = {'pubkey_hex': keys.public};