146 lines
5.1 KiB
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}',
|
|
);
|
|
}
|
|
}
|
|
|
|
}
|