import 'dart:convert'; import 'package:flutter/foundation.dart' show FlutterError; import 'package:flutter/services.dart' show rootBundle; import 'package:http/http.dart' as http; import 'push_notification_service.dart'; /// Mattermost 자동 로그인 + FCM 디바이스 토큰 서버 등록 서비스. class MattermostAuthService { final PushNotificationService _pushService; String? _serverUrl; String? _authToken; String? _userId; String? _sessionId; String? get serverUrl => _serverUrl; bool get isLoggedIn => _authToken != null; MattermostAuthService(this._pushService); /// assets/mattermost_credentials.json 로드 → 로그인 → FCM 등록까지 자동 수행. Future autoLoginAndRegister() async { final creds = await _loadCredentials(); if (creds == null) { print('[MattermostAuth] Credentials asset not found, skipping auto login.'); return; } _serverUrl = creds['serverUrl']!; print('[MattermostAuth] Logging in to $_serverUrl ...'); await _login(creds['loginId']!, creds['password']!); // FCM 토큰이 이미 있으면 바로 등록, 없으면 콜백으로 대기 final existingToken = await _pushService.getDeviceToken(); if (existingToken != null && existingToken.isNotEmpty) { print('[MattermostAuth] FCM token already available, registering ...'); await _registerDeviceToken(existingToken); } else { print('[MattermostAuth] FCM token not ready yet, waiting for callback ...'); } // FCM 토큰 발급/갱신 시 자동으로 서버에 등록 _pushService.onDeviceTokenReady = (deviceToken) async { print('[MattermostAuth] FCM token ready, registering with server ...'); await _registerDeviceToken(deviceToken); }; print('[MattermostAuth] Auto login & FCM registration complete.'); } Future?> _loadCredentials() async { final String jsonStr; try { jsonStr = await rootBundle.loadString('assets/mattermost_credentials.json'); } on FlutterError { return null; } final map = json.decode(jsonStr) as Map; return { 'serverUrl': map['serverUrl'] as String, 'loginId': map['loginId'] as String, 'password': map['password'] as String, }; } /// POST /api/v4/users/login → Token 헤더에서 인증 토큰 추출. Future _login(String loginId, String password) async { final url = Uri.parse('$_serverUrl/api/v4/users/login'); final response = await http.post( url, headers: {'Content-Type': 'application/json'}, body: json.encode({'login_id': loginId, 'password': password}), ); if (response.statusCode != 200) { throw Exception( '[MattermostAuth] Login failed (${response.statusCode}): ${response.body}', ); } _authToken = response.headers['token']; if (_authToken == null) { throw Exception('[MattermostAuth] Login response missing Token header'); } final body = json.decode(response.body) as Map; _userId = body['id'] as String?; _sessionId = body['session_id'] as String? ?? body['id'] as String?; print('[MattermostAuth] Login OK - userId=$_userId sessionId=$_sessionId'); // 네이티브 측에 인증 토큰 저장 (ACK, 답장 등에 사용) await _pushService.setAuthToken(_serverUrl!, _authToken!); // 서버 config에서 signing key 가져와 네이티브에 저장 await _fetchAndStoreSigningKey(); } /// GET /api/v4/config/client?format=old → AsymmetricSigningPublicKey를 네이티브에 저장. Future _fetchAndStoreSigningKey() async { try { final url = Uri.parse('$_serverUrl/api/v4/config/client?format=old'); final response = await http.get( url, headers: {'Authorization': 'Bearer $_authToken'}, ); if (response.statusCode != 200) { print('[MattermostAuth] Failed to fetch config (${response.statusCode})'); return; } final config = json.decode(response.body) as Map; final signingKey = config['AsymmetricSigningPublicKey'] as String?; if (signingKey != null && signingKey.isNotEmpty) { await _pushService.setSigningKey(_serverUrl!, signingKey); print('[MattermostAuth] Signing key stored.'); } else { print('[MattermostAuth] No signing key in server config.'); } } catch (e) { print('[MattermostAuth] Failed to fetch signing key: $e'); } } /// PUT /api/v4/users/sessions/device → device_id 등록. Future _registerDeviceToken(String deviceToken) async { final url = Uri.parse('$_serverUrl/api/v4/users/sessions/device'); final response = await http.put( url, headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $_authToken', }, body: json.encode({'device_id': deviceToken}), ); if (response.statusCode == 200) { print('[MattermostAuth] FCM device token registered successfully.'); } else { print( '[MattermostAuth] FCM registration failed (${response.statusCode}): ${response.body}', ); } } }