From a627deab515f4f918cc9cbedaaf105027ffed0cc Mon Sep 17 00:00:00 2001 From: stopflock Date: Sun, 4 Oct 2026 20:05:33 -0500 Subject: [PATCH] bool to handle potential future osm api behavior --- lib/dev_config.dart | 10 ++++++ lib/services/auth_service.dart | 61 +++++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/lib/dev_config.dart b/lib/dev_config.dart index bf7f6ed..2b9eee9 100644 --- a/lib/dev_config.dart +++ b/lib/dev_config.dart @@ -49,6 +49,16 @@ double topPositionWithSafeArea(double baseTop, EdgeInsets safeArea) { return baseTop + safeArea.top; } +// Whether to proactively check blocks/active *before* attempting to fetch +// the username during login. Current OSM behavior: user/details returns 403 +// for blocked accounts, so we check blocks/active first (it's documented as +// accessible even while blocked) to detect this reliably instead of getting +// an unexplained 403. Flip to false once OSM allows user/details to succeed +// for blocked accounts too, so login can complete normally and rely on the +// regular checkActiveBlock() triggers (launch/resume/queue/test connection) +// to surface the block warning instead. +const bool kCheckBlockBeforeUsernameFetch = true; + // Client name for OSM uploads ("created_by" tag) const String kClientName = 'DeFlock'; // Note: Version is now dynamically retrieved from VersionService diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 06aeece..c0c7aef 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -9,6 +9,7 @@ import 'package:shared_preferences/shared_preferences.dart'; /// Handles PKCE OAuth login with OpenStreetMap. import '../keys.dart'; +import '../dev_config.dart'; import '../app_state.dart' show UploadMode; import 'http_client.dart'; import 'osm_block_service.dart'; @@ -131,27 +132,49 @@ class AuthService { final prefs = await SharedPreferences.getInstance(); await prefs.setString(_tokenKey, tokenJson); // Save token for current mode - // Check for an active block *before* fetching the username or anything - // else. A blocked account's OAuth token exchange succeeds normally, - // but nearly every other authenticated endpoint (including - // user/details) returns 403. The blocks/active endpoint is explicitly - // documented as accessible even while blocked, so checking it first - // lets us detect this case reliably instead of getting a mysterious - // 403 from _fetchUsername with no way to tell why. - final isBlocked = await _blockService.checkActiveBlock( - accessToken: token.accessToken, - uploadMode: _mode, - ); - if (isBlocked == true) { - debugPrint('AuthService: Login succeeded but account has an active block'); - throw AccountBlockedException(); + if (kCheckBlockBeforeUsernameFetch) { + // Check for an active block *before* fetching the username or + // anything else. As of writing, a blocked account's OAuth token + // exchange succeeds normally, but nearly every other authenticated + // endpoint (including user/details) returns 403. The blocks/active + // endpoint is explicitly documented as accessible even while + // blocked, so checking it first lets us detect this case reliably + // instead of getting a mysterious 403 from _fetchUsername with no + // way to tell why. + final isBlocked = await _blockService.checkActiveBlock( + accessToken: token.accessToken, + uploadMode: _mode, + ); + if (isBlocked == true) { + debugPrint('AuthService: Login succeeded but account has an active block'); + throw AccountBlockedException(); + } } - // Fetching the username can still fail for other reasons even though - // the OAuth token exchange succeeded. Don't swallow that - the token - // is already saved, so the caller needs to know the login isn't - // actually usable rather than silently treating it as "not logged in". - _displayName = await _fetchUsername(token.accessToken!); + // Fetching the username can still fail even though the OAuth token + // exchange succeeded (e.g. if OSM ever allows this call to succeed for + // blocked accounts, kCheckBlockBeforeUsernameFetch would be false and + // we'd only find out here). Don't swallow that - the token is already + // saved, so the caller needs to know the login isn't actually usable + // rather than silently treating it as "not logged in". + try { + _displayName = await _fetchUsername(token.accessToken!); + } on AuthApiException { + // When we skipped the proactive check above, a 403 here could still + // mean the account is blocked - check blocks/active now so we can + // report that specifically instead of a generic auth failure. + if (!kCheckBlockBeforeUsernameFetch) { + final isBlocked = await _blockService.checkActiveBlock( + accessToken: token.accessToken, + uploadMode: _mode, + ); + if (isBlocked == true) { + debugPrint('AuthService: user/details failed and account has an active block'); + throw AccountBlockedException(); + } + } + rethrow; + } return _displayName; } on AccountBlockedException { rethrow;