forked from baron/baron-sso
namecard 연동
This commit is contained in:
38
frontend/lib/core/services/audit_service.dart
Normal file
38
frontend/lib/core/services/audit_service.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
|
||||
class AuditService {
|
||||
static final String _baseUrl = dotenv.env['BACKEND_URL'] ?? 'http://localhost:3000';
|
||||
|
||||
static Future<void> logEvent({
|
||||
required String userId,
|
||||
required String eventType,
|
||||
required String status,
|
||||
String? details,
|
||||
}) async {
|
||||
final url = Uri.parse('$_baseUrl/api/v1/audit');
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode({
|
||||
'user_id': userId,
|
||||
'event_type': eventType,
|
||||
'status': status,
|
||||
'details': details,
|
||||
'timestamp': DateTime.now().toIso8601String(),
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||
print("Audit log sent successfully");
|
||||
} else {
|
||||
print("Failed to send audit log: ${response.statusCode} ${response.body}");
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error sending audit log: $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
76
frontend/lib/core/services/auth_proxy_service.dart
Normal file
76
frontend/lib/core/services/auth_proxy_service.dart
Normal file
@@ -0,0 +1,76 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
|
||||
class AuthProxyService {
|
||||
static final String _baseUrl = dotenv.env['BACKEND_URL'] ?? 'http://localhost:3000';
|
||||
|
||||
static Future<Map<String, dynamic>> initEnchantedLink(String loginId) async {
|
||||
final url = Uri.parse('$_baseUrl/api/v1/auth/enchanted-link/init');
|
||||
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode({
|
||||
'loginId': loginId,
|
||||
'uri': 'http://localhost:5000', // Use 5000 as it's definitely allowed
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return jsonDecode(response.body);
|
||||
} else {
|
||||
throw Exception('Failed to init login: ${response.body}');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> pollEnchantedLink(String pendingRef) async {
|
||||
final url = Uri.parse('$_baseUrl/api/v1/auth/enchanted-link/poll');
|
||||
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode({
|
||||
'pendingRef': pendingRef,
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return jsonDecode(response.body);
|
||||
} else {
|
||||
throw Exception('Polling failed: ${response.body}');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> verifyMagicLink(String token) async {
|
||||
final url = Uri.parse('$_baseUrl/api/v1/auth/magic-link/verify');
|
||||
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode({
|
||||
'token': token,
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Verification failed: ${response.body}');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> logError(String message) async {
|
||||
final url = Uri.parse('$_baseUrl/api/v1/client-log');
|
||||
try {
|
||||
await http.post(
|
||||
url,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode({
|
||||
'level': 'ERROR',
|
||||
'message': message,
|
||||
}),
|
||||
);
|
||||
} catch (_) {
|
||||
// Ignore logging errors to prevent loops
|
||||
}
|
||||
}
|
||||
}
|
||||
13
frontend/lib/core/services/web_auth_integration.dart
Normal file
13
frontend/lib/core/services/web_auth_integration.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'web_auth_integration_stub.dart'
|
||||
if (dart.library.html) 'web_auth_integration_web.dart';
|
||||
|
||||
abstract class WebAuthIntegration {
|
||||
static void sendLoginSuccess(String token) {
|
||||
// Platform-specific implementation
|
||||
implSendLoginSuccess(token);
|
||||
}
|
||||
|
||||
static bool isPopup() {
|
||||
return implIsPopup();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
void implSendLoginSuccess(String token) {
|
||||
// No-op on non-web platforms
|
||||
print("Not on web: Login Success with token: $token");
|
||||
}
|
||||
|
||||
bool implIsPopup() {
|
||||
return false;
|
||||
}
|
||||
37
frontend/lib/core/services/web_auth_integration_web.dart
Normal file
37
frontend/lib/core/services/web_auth_integration_web.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
import 'dart:html' as html;
|
||||
|
||||
void implSendLoginSuccess(String token) {
|
||||
final message = {'type': 'LOGIN_SUCCESS', 'token': token};
|
||||
bool sent = false;
|
||||
|
||||
// 1. Try postMessage
|
||||
if (html.window.opener != null) {
|
||||
try {
|
||||
html.window.opener!.postMessage(message, '*');
|
||||
sent = true;
|
||||
print("Sent login success message to opener");
|
||||
} catch (e) {
|
||||
print("Failed to postMessage: $e");
|
||||
}
|
||||
|
||||
// 2. Fallback: Redirect opener directly (Force refresh with token)
|
||||
try {
|
||||
// Only redirect if it's localhost:8000 to be safe, or just do it.
|
||||
// This will cause the parent window to reload, which is fine for login.
|
||||
html.window.opener!.location.href = "http://localhost:8000?token=$token";
|
||||
sent = true;
|
||||
} catch (e) {
|
||||
print("Failed to redirect opener: $e");
|
||||
}
|
||||
}
|
||||
|
||||
if (!sent) {
|
||||
print("No opener found. Redirecting current window to target.");
|
||||
// Fallback: Redirect THIS window to localhost:8000 with token
|
||||
html.window.location.href = "http://localhost:8000?token=$token";
|
||||
}
|
||||
}
|
||||
|
||||
bool implIsPopup() {
|
||||
return html.window.opener != null;
|
||||
}
|
||||
Reference in New Issue
Block a user