nomadcode/lib/services/mattermost_auth_service.dart

146 lines
5.1 KiB
Dart

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<void> 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<Map<String, String>?> _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<String, dynamic>;
return {
'serverUrl': map['serverUrl'] as String,
'loginId': map['loginId'] as String,
'password': map['password'] as String,
};
}
/// POST /api/v4/users/login → Token 헤더에서 인증 토큰 추출.
Future<void> _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<String, dynamic>;
_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<void> _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<String, dynamic>;
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<void> _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}',
);
}
}
}