forked from baron/baron-sso
userfront 런타임 BACKEND_URL fallback 수정
This commit is contained in:
@@ -1,18 +1,10 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'runtime_env.dart';
|
||||||
|
|
||||||
class AuditService {
|
class AuditService {
|
||||||
static String _envOrDefault(String key, String fallback) {
|
static String get _baseUrl => runtimeBackendUrl();
|
||||||
if (!dotenv.isInitialized) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
return dotenv.env[key] ?? fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String get _baseUrl =>
|
|
||||||
_envOrDefault('BACKEND_URL', 'https://sso.hmac.kr');
|
|
||||||
|
|
||||||
static Future<void> logEvent({
|
static Future<void> logEvent({
|
||||||
required String userId,
|
required String userId,
|
||||||
|
|||||||
@@ -1,41 +1,16 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|
||||||
import 'package:userfront/i18n.dart';
|
import 'package:userfront/i18n.dart';
|
||||||
import 'http_client.dart';
|
import 'http_client.dart';
|
||||||
import 'auth_token_store.dart';
|
import 'auth_token_store.dart';
|
||||||
import 'log_policy.dart';
|
import 'log_policy.dart';
|
||||||
|
import 'runtime_env.dart';
|
||||||
|
|
||||||
class AuthProxyService {
|
class AuthProxyService {
|
||||||
static String _envOrDefault(String key, String fallback) {
|
static String get _baseUrl => runtimeBackendUrl();
|
||||||
if (!dotenv.isInitialized) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
final value = dotenv.env[key];
|
|
||||||
if (value == null || value.trim().isEmpty) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String _fallbackOrigin() {
|
|
||||||
try {
|
|
||||||
final origin = Uri.base.origin;
|
|
||||||
if (origin.isNotEmpty && origin != 'null') {
|
|
||||||
return origin;
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
return 'http://sso.hmac.kr';
|
|
||||||
}
|
|
||||||
|
|
||||||
static String get _baseUrl {
|
|
||||||
final rawUrl = _envOrDefault('BACKEND_URL', _fallbackOrigin());
|
|
||||||
// 배포 환경에서 $ 기호나 공백이 섞여 들어오는 경우를 방지하기 위해 정제합니다.
|
|
||||||
return rawUrl.replaceAll(r'$', '').trim().replaceAll(RegExp(r'/$'), '');
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool get _isProd {
|
static bool get _isProd {
|
||||||
final env = _envOrDefault('APP_ENV', 'dev').toLowerCase();
|
final env = envOrDefault('APP_ENV', 'dev').toLowerCase();
|
||||||
return LogPolicy.isProductionEnv(env);
|
return LogPolicy.isProductionEnv(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +131,7 @@ class AuthProxyService {
|
|||||||
bool? drySend,
|
bool? drySend,
|
||||||
}) async {
|
}) async {
|
||||||
final url = Uri.parse('$_baseUrl/api/v1/auth/enchanted-link/init');
|
final url = Uri.parse('$_baseUrl/api/v1/auth/enchanted-link/init');
|
||||||
final userfrontUrl = _envOrDefault('USERFRONT_URL', _fallbackOrigin());
|
final userfrontUrl = runtimeUserfrontUrl();
|
||||||
|
|
||||||
final body = <String, dynamic>{'loginId': loginId, 'uri': userfrontUrl};
|
final body = <String, dynamic>{'loginId': loginId, 'uri': userfrontUrl};
|
||||||
if (_shouldSendDrySend(drySend)) {
|
if (_shouldSendDrySend(drySend)) {
|
||||||
@@ -897,10 +872,10 @@ class AuthProxyService {
|
|||||||
if (!_canSendClientLog()) {
|
if (!_canSendClientLog()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final appEnv = _envOrDefault('APP_ENV', 'dev');
|
final appEnv = envOrDefault('APP_ENV', 'dev');
|
||||||
final productionDebugFlag = _envOrDefault(
|
final productionDebugFlag = envOrDefault(
|
||||||
'CLIENT_LOG_DEBUG',
|
'CLIENT_LOG_DEBUG',
|
||||||
_envOrDefault('USERFRONT_DEBUG_LOG', ''),
|
envOrDefault('USERFRONT_DEBUG_LOG', ''),
|
||||||
);
|
);
|
||||||
if (!LogPolicy.shouldRelayClientLog(
|
if (!LogPolicy.shouldRelayClientLog(
|
||||||
level: level,
|
level: level,
|
||||||
|
|||||||
34
userfront/lib/core/services/runtime_env.dart
Normal file
34
userfront/lib/core/services/runtime_env.dart
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
|
||||||
|
String runtimeOriginFallback() {
|
||||||
|
try {
|
||||||
|
final origin = Uri.base.origin;
|
||||||
|
if (origin.isNotEmpty && origin != 'null') {
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
return 'https://sso-test.hmac.kr';
|
||||||
|
}
|
||||||
|
|
||||||
|
String envOrDefault(String key, String fallback) {
|
||||||
|
if (!dotenv.isInitialized) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
final value = dotenv.env[key];
|
||||||
|
if (value == null || value.trim().isEmpty) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sanitizedUrl(String value) {
|
||||||
|
return value.replaceAll(r'$', '').trim().replaceAll(RegExp(r'/$'), '');
|
||||||
|
}
|
||||||
|
|
||||||
|
String runtimeBackendUrl() {
|
||||||
|
return sanitizedUrl(envOrDefault('BACKEND_URL', runtimeOriginFallback()));
|
||||||
|
}
|
||||||
|
|
||||||
|
String runtimeUserfrontUrl() {
|
||||||
|
return sanitizedUrl(envOrDefault('USERFRONT_URL', runtimeOriginFallback()));
|
||||||
|
}
|
||||||
@@ -1,21 +1,14 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../../../core/services/auth_token_store.dart';
|
import '../../../../core/services/auth_token_store.dart';
|
||||||
import '../../../../core/services/http_client.dart';
|
import '../../../../core/services/http_client.dart';
|
||||||
|
import '../../../../core/services/runtime_env.dart';
|
||||||
import 'package:userfront/i18n.dart';
|
import 'package:userfront/i18n.dart';
|
||||||
import 'models.dart';
|
import 'models.dart';
|
||||||
|
|
||||||
String _envOrDefault(String key, String fallback) {
|
String get _baseUrl => runtimeBackendUrl();
|
||||||
if (!dotenv.isInitialized) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
return dotenv.env[key] ?? fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
String get _baseUrl => _envOrDefault('BACKEND_URL', 'https://sso.hmac.kr');
|
|
||||||
|
|
||||||
Future<AuditPage> _fetchAuthTimelinePage({String? cursor}) async {
|
Future<AuditPage> _fetchAuthTimelinePage({String? cursor}) async {
|
||||||
final queryParameters = <String, String>{'limit': '20'};
|
final queryParameters = <String, String>{'limit': '20'};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|
||||||
import 'package:userfront/core/services/auth_proxy_service.dart';
|
import 'package:userfront/core/services/auth_proxy_service.dart';
|
||||||
import 'package:userfront/core/services/auth_token_store.dart';
|
import 'package:userfront/core/services/auth_token_store.dart';
|
||||||
import 'package:userfront/core/services/http_client.dart';
|
import 'package:userfront/core/services/http_client.dart';
|
||||||
|
import 'package:userfront/core/services/runtime_env.dart';
|
||||||
|
|
||||||
class LinkedRp {
|
class LinkedRp {
|
||||||
final String id;
|
final String id;
|
||||||
@@ -62,16 +62,9 @@ class LinkedRpsNotifier extends AsyncNotifier<List<LinkedRp>> {
|
|||||||
return _fetchLinkedRps();
|
return _fetchLinkedRps();
|
||||||
}
|
}
|
||||||
|
|
||||||
String _envOrDefault(String key, String fallback) {
|
|
||||||
if (!dotenv.isInitialized) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
return dotenv.env[key] ?? fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<LinkedRp>> _fetchLinkedRps() async {
|
Future<List<LinkedRp>> _fetchLinkedRps() async {
|
||||||
try {
|
try {
|
||||||
final baseUrl = _envOrDefault('BACKEND_URL', 'https://sso.hmac.kr');
|
final baseUrl = runtimeBackendUrl();
|
||||||
final url = Uri.parse('$baseUrl/api/v1/user/rp/linked');
|
final url = Uri.parse('$baseUrl/api/v1/user/rp/linked');
|
||||||
|
|
||||||
final useCookie = AuthTokenStore.usesCookie();
|
final useCookie = AuthTokenStore.usesCookie();
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../../../core/services/auth_proxy_service.dart';
|
import '../../../../core/services/auth_proxy_service.dart';
|
||||||
import '../../../../core/services/auth_token_store.dart';
|
import '../../../../core/services/auth_token_store.dart';
|
||||||
import '../../../../core/services/http_client.dart';
|
import '../../../../core/services/http_client.dart';
|
||||||
|
import '../../../../core/services/runtime_env.dart';
|
||||||
import '../models.dart';
|
import '../models.dart';
|
||||||
|
|
||||||
class UserSessionsNotifier extends AsyncNotifier<List<UserSessionSummary>> {
|
class UserSessionsNotifier extends AsyncNotifier<List<UserSessionSummary>> {
|
||||||
@@ -14,15 +14,8 @@ class UserSessionsNotifier extends AsyncNotifier<List<UserSessionSummary>> {
|
|||||||
return _fetchSessions();
|
return _fetchSessions();
|
||||||
}
|
}
|
||||||
|
|
||||||
String _envOrDefault(String key, String fallback) {
|
|
||||||
if (!dotenv.isInitialized) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
return dotenv.env[key] ?? fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<UserSessionSummary>> _fetchSessions() async {
|
Future<List<UserSessionSummary>> _fetchSessions() async {
|
||||||
final baseUrl = _envOrDefault('BACKEND_URL', 'https://sso.hmac.kr');
|
final baseUrl = runtimeBackendUrl();
|
||||||
final url = Uri.parse('$baseUrl/api/v1/user/sessions');
|
final url = Uri.parse('$baseUrl/api/v1/user/sessions');
|
||||||
|
|
||||||
final useCookie = AuthTokenStore.usesCookie();
|
final useCookie = AuthTokenStore.usesCookie();
|
||||||
|
|||||||
@@ -1,20 +1,12 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|
||||||
import 'package:userfront/i18n.dart';
|
import 'package:userfront/i18n.dart';
|
||||||
import '../models/user_profile_model.dart';
|
import '../models/user_profile_model.dart';
|
||||||
import '../../../../core/services/auth_token_store.dart';
|
import '../../../../core/services/auth_token_store.dart';
|
||||||
import '../../../../core/services/http_client.dart';
|
import '../../../../core/services/http_client.dart';
|
||||||
|
import '../../../../core/services/runtime_env.dart';
|
||||||
|
|
||||||
class ProfileRepository {
|
class ProfileRepository {
|
||||||
static String _envOrDefault(String key, String fallback) {
|
static String get _baseUrl => runtimeBackendUrl();
|
||||||
if (!dotenv.isInitialized) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
return dotenv.env[key] ?? fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String get _baseUrl =>
|
|
||||||
_envOrDefault('BACKEND_URL', 'https://sso.hmac.kr');
|
|
||||||
|
|
||||||
// Helper to get session token
|
// Helper to get session token
|
||||||
static Future<String?> _getToken() async {
|
static Future<String?> _getToken() async {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart' hide tr;
|
import 'package:easy_localization/easy_localization.dart' hide tr;
|
||||||
@@ -161,10 +162,20 @@ bool _shouldRunStartupSessionRecovery(Uri uri) {
|
|||||||
return !isPublicAuthPath(path, uri);
|
return !isPublicAuthPath(path, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _loadRuntimeEnv() async {
|
||||||
|
for (final fileName in const ['assets/.env', '.env']) {
|
||||||
|
try {
|
||||||
|
await dotenv.load(fileName: fileName);
|
||||||
|
return;
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
usePathUrlStrategy();
|
usePathUrlStrategy();
|
||||||
await EasyLocalization.ensureInitialized();
|
await EasyLocalization.ensureInitialized();
|
||||||
|
await _loadRuntimeEnv();
|
||||||
LocaleRegistry.primeWithDefaults();
|
LocaleRegistry.primeWithDefaults();
|
||||||
|
|
||||||
// 1. Global Error Handling
|
// 1. Global Error Handling
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ log_format json_combined escape=json
|
|||||||
|
|
||||||
server {
|
server {
|
||||||
listen 5000;
|
listen 5000;
|
||||||
|
absolute_redirect off;
|
||||||
|
port_in_redirect off;
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
include /etc/nginx/mime.types;
|
include /etc/nginx/mime.types;
|
||||||
|
|||||||
Reference in New Issue
Block a user