mirror of
https://github.com/block/buzz.git
synced 2026-10-27 12:40:30 +00:00
Forward iOS cold-start invite URLs, offer explicit identity creation or matching-key import, and discover account-saved communities through the supported API. Co-authored-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz> Signed-off-by: Wes <wesbillman@users.noreply.github.com>
88 lines
3.4 KiB
Dart
88 lines
3.4 KiB
Dart
import '../deeplink/deep_link.dart';
|
|
import 'builderlab_account.dart';
|
|
import 'hosted_environment.dart';
|
|
|
|
/// Account-saved destinations, not evidence that this identity is a member.
|
|
/// Keep the existing hosted environment boundary and normal relay admission.
|
|
Future<List<AddCommunityDeepLink>> loadKnownHostedCommunities(
|
|
BuilderlabAccountClient account,
|
|
) async {
|
|
final response = await account.post('/v1/buzz/known-communities/list', {});
|
|
// Protobuf JSON omits an empty repeated field.
|
|
final rows = response['communities'] ?? <dynamic>[];
|
|
if (response['error'] != null || rows is! List) {
|
|
throw AccountFailure.invalidResponse;
|
|
}
|
|
final communities = <String, AddCommunityDeepLink>{};
|
|
for (final row in rows) {
|
|
if (row is! Map<String, dynamic> || row['community_url'] is! String) {
|
|
throw AccountFailure.invalidResponse;
|
|
}
|
|
final relay = Uri.tryParse(row['community_url'] as String);
|
|
// The account can also save destinations this hosted build cannot enter.
|
|
if (relay == null ||
|
|
relay.scheme != 'wss' ||
|
|
!RegExp(r'^[a-z0-9]+(?:[.-][a-z0-9]+)*$').hasMatch(relay.host) ||
|
|
!HostedEnvironment.supportsRelay(relay)) {
|
|
continue;
|
|
}
|
|
final canonical = Uri(scheme: 'wss', host: relay.host);
|
|
communities.putIfAbsent(
|
|
canonical.host,
|
|
() => AddCommunityDeepLink(
|
|
relayUrl: canonical.toString(),
|
|
name: canonical.host,
|
|
),
|
|
);
|
|
}
|
|
return List.unmodifiable(communities.values);
|
|
}
|
|
|
|
/// Validated, active communities joined by the signed-in Builderlab identity.
|
|
/// Discovery never grants admission; each target still goes through HostedAdmission.
|
|
Future<List<AddCommunityDeepLink>> loadHostedCommunities(
|
|
BuilderlabAccountClient account,
|
|
) async {
|
|
final response = await account.post('/v1/buzz/communities/joined', {});
|
|
final rows = response['communities'];
|
|
if (response['error'] != null || rows is! List) {
|
|
throw AccountFailure.invalidResponse;
|
|
}
|
|
final communities = <String, AddCommunityDeepLink>{};
|
|
for (final row in rows) {
|
|
if (row is! Map<String, dynamic>) throw AccountFailure.invalidResponse;
|
|
final archived = row['archived_at'];
|
|
if (archived != null) {
|
|
if (archived is! String || archived.isEmpty) {
|
|
throw AccountFailure.invalidResponse;
|
|
}
|
|
continue;
|
|
}
|
|
final host = row['normalized_host'];
|
|
final name = row['name'];
|
|
if (host is! String || name is! String || name.trim().isEmpty) {
|
|
throw AccountFailure.invalidResponse;
|
|
}
|
|
final relay = Uri.tryParse(host.contains('://') ? host : 'wss://$host');
|
|
if (relay == null ||
|
|
relay.scheme != 'wss' ||
|
|
!RegExp(r'^[a-z0-9]+(?:[.-][a-z0-9]+)*$').hasMatch(relay.host) ||
|
|
relay.userInfo.isNotEmpty ||
|
|
relay.hasQuery ||
|
|
relay.hasFragment ||
|
|
(relay.path.isNotEmpty && relay.path != '/') ||
|
|
(relay.hasPort && relay.port != 443)) {
|
|
throw AccountFailure.invalidResponse;
|
|
}
|
|
// A hosted listing can contain communities this build cannot enter.
|
|
// Never redirect the account session or discard otherwise usable entries.
|
|
if (!HostedEnvironment.supportsRelay(relay)) continue;
|
|
final canonical = Uri(scheme: 'wss', host: relay.host);
|
|
communities.putIfAbsent(
|
|
canonical.host,
|
|
() => AddCommunityDeepLink(relayUrl: canonical.toString(), name: name),
|
|
);
|
|
}
|
|
return List.unmodifiable(communities.values);
|
|
}
|