첫 커밋: 로컬 프로젝트 업로드
45
baron-sso/userfront/.gitignore
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.build/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
.swiftpm/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
**/ios/Flutter/.last_build_id
|
||||
.dart_tool/
|
||||
.flutter-plugins-dependencies
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
/coverage/
|
||||
|
||||
# Symbolication related
|
||||
app.*.symbols
|
||||
|
||||
# Obfuscation related
|
||||
app.*.map.json
|
||||
|
||||
# Android Studio will place build artifacts here
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
36
baron-sso/userfront/.metadata
Normal file
@@ -0,0 +1,36 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: "f6ff1529fd6d8af5f706051d9251ac9231c83407"
|
||||
channel: "stable"
|
||||
|
||||
project_type: app
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407
|
||||
base_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407
|
||||
- platform: android
|
||||
create_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407
|
||||
base_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407
|
||||
- platform: ios
|
||||
create_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407
|
||||
base_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407
|
||||
- platform: web
|
||||
create_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407
|
||||
base_revision: f6ff1529fd6d8af5f706051d9251ac9231c83407
|
||||
|
||||
# User provided section
|
||||
|
||||
# List of Local paths (relative to this file) that should be
|
||||
# ignored by the migrate tool.
|
||||
#
|
||||
# Files that are not part of the templates will be ignored by default.
|
||||
unmanaged_files:
|
||||
- 'lib/main.dart'
|
||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
||||
38
baron-sso/userfront/Dockerfile
Normal file
@@ -0,0 +1,38 @@
|
||||
FROM ghcr.io/cirruslabs/flutter:3.38.0 AS dev
|
||||
ENV RUN_FLUTTER_AS_ROOT=true
|
||||
WORKDIR /workspace
|
||||
COPY scripts ./scripts
|
||||
COPY locales ./locales
|
||||
COPY userfront ./userfront
|
||||
WORKDIR /workspace/userfront
|
||||
RUN flutter pub get
|
||||
EXPOSE 5000
|
||||
CMD ["sh", "./scripts/dev-server.sh"]
|
||||
|
||||
# Stage 1: Build Flutter
|
||||
FROM ghcr.io/cirruslabs/flutter:3.38.0 AS build
|
||||
ENV RUN_FLUTTER_AS_ROOT=true
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
# Get dependencies and build for web
|
||||
RUN /bin/sh ./scripts/sync_userfront_locales.sh
|
||||
WORKDIR /app/userfront
|
||||
RUN flutter pub get
|
||||
RUN rm -rf build/web && flutter build web --release --wasm
|
||||
|
||||
FROM node:24-alpine AS optimize
|
||||
WORKDIR /work
|
||||
COPY --from=build /app/userfront/build/web /work/build/web
|
||||
COPY userfront/scripts/optimize-web-build.mjs /work/scripts/optimize-web-build.mjs
|
||||
RUN node /work/scripts/optimize-web-build.mjs /work/build/web
|
||||
|
||||
# Stage 2: Serve with Nginx
|
||||
FROM alpine:3.23 AS production
|
||||
RUN apk add --no-cache nginx nginx-mod-http-brotli
|
||||
# Copy built assets
|
||||
COPY --from=optimize /work/build/web /usr/share/nginx/html
|
||||
# Copy custom Nginx config
|
||||
COPY userfront/nginx.conf /etc/nginx/http.d/default.conf
|
||||
|
||||
EXPOSE 5000
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
28
baron-sso/userfront/analysis_options.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
# This file configures the analyzer, which statically analyzes Dart code to
|
||||
# check for errors, warnings, and lints.
|
||||
#
|
||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||
# invoked from the command line by running `flutter analyze`.
|
||||
|
||||
# The following line activates a set of recommended lints for Flutter apps,
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
# included above or to enable additional rules. A list of all available lints
|
||||
# and their documentation is published at https://dart.dev/lints.
|
||||
#
|
||||
# Instead of disabling a lint rule for the entire project in the
|
||||
# section below, it can also be suppressed for a single line of code
|
||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||
# producing the lint.
|
||||
rules:
|
||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
14
baron-sso/userfront/android/.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
.cxx/
|
||||
|
||||
# Remember to never publicly share your keystore.
|
||||
# See https://flutter.dev/to/reference-keystore
|
||||
key.properties
|
||||
**/*.keystore
|
||||
**/*.jks
|
||||
44
baron-sso/userfront/android/app/build.gradle.kts
Normal file
@@ -0,0 +1,44 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "kr.co.baroncs.userfront"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_17.toString()
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId = "kr.co.baroncs.userfront"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||
minSdk = flutter.minSdkVersion
|
||||
targetSdk = flutter.targetSdkVersion
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
46
baron-sso/userfront/android/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<application
|
||||
android:label="userfront"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||
|
||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
@@ -0,0 +1,5 @@
|
||||
package kr.co.baroncs.userfront
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity : FlutterActivity()
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
24
baron-sso/userfront/android/build.gradle.kts
Normal file
@@ -0,0 +1,24 @@
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
val newBuildDir: Directory =
|
||||
rootProject.layout.buildDirectory
|
||||
.dir("../../build")
|
||||
.get()
|
||||
rootProject.layout.buildDirectory.value(newBuildDir)
|
||||
|
||||
subprojects {
|
||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
||||
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
||||
}
|
||||
subprojects {
|
||||
project.evaluationDependsOn(":app")
|
||||
}
|
||||
|
||||
tasks.register<Delete>("clean") {
|
||||
delete(rootProject.layout.buildDirectory)
|
||||
}
|
||||
2
baron-sso/userfront/android/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
5
baron-sso/userfront/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
|
||||
26
baron-sso/userfront/android/settings.gradle.kts
Normal file
@@ -0,0 +1,26 @@
|
||||
pluginManagement {
|
||||
val flutterSdkPath =
|
||||
run {
|
||||
val properties = java.util.Properties()
|
||||
file("local.properties").inputStream().use { properties.load(it) }
|
||||
val flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
|
||||
flutterSdkPath
|
||||
}
|
||||
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "8.11.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.2.20" apply false
|
||||
}
|
||||
|
||||
include(":app")
|
||||
BIN
baron-sso/userfront/assets/baron.ico
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
baron-sso/userfront/assets/fonts/NotoSansKR-Bold.ttf
Normal file
BIN
baron-sso/userfront/assets/fonts/NotoSansKR-Regular.ttf
Normal file
709
baron-sso/userfront/assets/translations/en.toml
Normal file
@@ -0,0 +1,709 @@
|
||||
[domain]
|
||||
|
||||
[domain.affiliation]
|
||||
affiliate = "Affiliate"
|
||||
general = "General"
|
||||
|
||||
[domain.company]
|
||||
baron = "Baron"
|
||||
halla = "Halla"
|
||||
hanmac = "Hanmac"
|
||||
jangheon = "Jangheon"
|
||||
ptc = "PTC"
|
||||
saman = "Saman"
|
||||
|
||||
[domain.tenant_type]
|
||||
company = "Company"
|
||||
company_group = "Company Group"
|
||||
organization = "Organization"
|
||||
personal = "Personal"
|
||||
user_group = "User Group"
|
||||
|
||||
[err.userfront]
|
||||
|
||||
[err.userfront.auth_proxy]
|
||||
consent_accept = "Failed to accept the consent request."
|
||||
consent_fetch = "Failed to load consent details."
|
||||
consent_reject = "Failed to reject the consent request."
|
||||
linked_app_revoke = "Failed to revoke the linked application."
|
||||
login_failed = "Login failed."
|
||||
oidc_accept = "OIDC Accept"
|
||||
password_reset_complete = "Failed to complete the password reset."
|
||||
password_reset_init = "Failed to start the password reset."
|
||||
|
||||
[err.userfront.profile]
|
||||
load_failed = "Failed to load the profile."
|
||||
password_change_failed = "Password Change Failed"
|
||||
send_code_failed = "Failed to send the verification code."
|
||||
update_failed = "Failed to update the profile."
|
||||
verify_code_failed = "Verification failed."
|
||||
|
||||
[err.userfront.session]
|
||||
missing = "No active session was found."
|
||||
|
||||
[msg.userfront]
|
||||
greeting = "Hello, {name}."
|
||||
|
||||
[msg.userfront.audit]
|
||||
browser = "Browser: {value}"
|
||||
date = "Date: {value}"
|
||||
device = "Device: {value}"
|
||||
end = "No more items to show."
|
||||
filtered_empty = "No sign-in history matches the active session filter."
|
||||
ip = "IP address: {value}"
|
||||
load_more_error = "Could not load more history."
|
||||
result = "Result: {value}"
|
||||
session_id = "Session ID: {value}"
|
||||
status = "Status: pending"
|
||||
|
||||
[msg.userfront.consent]
|
||||
accept_error = "Failed to process consent: {error}"
|
||||
client_id = "Client ID: {id}"
|
||||
client_unknown = "Unknown application"
|
||||
description = "The service below is requesting access to your account information.\\\\nPlease choose whether to continue."
|
||||
load_error = "Failed to load consent information: {error}"
|
||||
missing_redirect = "Consent was processed, but the redirect URL was missing."
|
||||
redirect_notice = "After consent, you will be redirected automatically."
|
||||
scope_count = "Total {count}"
|
||||
|
||||
[msg.userfront.consent.cancel]
|
||||
confirm = "If you cancel consent, you will not be able to use this service. Do you want to cancel?"
|
||||
error = "An error occurred while cancelling consent: {error}"
|
||||
|
||||
[msg.userfront.consent.scope]
|
||||
email = "Email address (account identification and notifications)"
|
||||
offline_access = "Offline access (keep signed in)"
|
||||
openid = "OpenID authentication information (signin session check)"
|
||||
phone = "Phone number (identity verification and notifications)"
|
||||
profile = "Basic profile information (name, user identifier)"
|
||||
|
||||
[msg.userfront.dashboard]
|
||||
approved_device = "Approved device: {device}"
|
||||
approved_ip = "Approved IP: {ip}"
|
||||
audit_empty = "No recent sign-in activity."
|
||||
audit_load_error = "Could not load sign-in history."
|
||||
auto_login_supported = "You can sign in without an extra login when opening this linked app."
|
||||
auth_method = "Auth method: {method}"
|
||||
client_id = "Client ID: {id}"
|
||||
client_id_missing = "No client ID available."
|
||||
current_status = "Current status: {status}"
|
||||
last_auth = "Last signed in: {value}"
|
||||
link_status = "Link status: {status}"
|
||||
link_missing = "This app does not have a launch URL configured."
|
||||
link_open_error = "Could not open the app link."
|
||||
render_error = "Dashboard render error: {error}"
|
||||
session_id_copied = "Session ID copied."
|
||||
|
||||
[msg.userfront.dashboard.activities]
|
||||
empty = "No linked apps yet."
|
||||
empty_detail = "Linked apps and their latest activity will appear here."
|
||||
error = "Could not load linked apps."
|
||||
|
||||
[msg.userfront.dashboard.sessions]
|
||||
browser = "Browser: {value}"
|
||||
empty = "No active sessions."
|
||||
empty_detail = "Devices signed in with this account will appear here."
|
||||
error = "Could not load sessions."
|
||||
os = "OS: {value}"
|
||||
recent_app = "Recent app: {app}"
|
||||
session_id = "Session ID: {id}"
|
||||
|
||||
[msg.userfront.dashboard.sessions.revoke]
|
||||
confirm = "End the session for {target}?\nThat device will need to sign in again."
|
||||
error = "Could not end the session: {error}"
|
||||
success = "The session has been ended."
|
||||
|
||||
[msg.userfront.dashboard.approved_session]
|
||||
copy_click = "{label}: {id}\\\\\\\\\\\\\\\\nClick to copy."
|
||||
copy_tap = "{label}: {id}\\\\\\\\\\\\\\\\nTap to copy."
|
||||
none = "No {label}"
|
||||
|
||||
[msg.userfront.dashboard.revoke]
|
||||
confirm = "Disconnect {app}?\\\\\\\\\\\\\\\\nYou will need to grant access again the next time you sign in."
|
||||
error = "Could not disconnect the app: {error}"
|
||||
success = "{app} has been disconnected."
|
||||
|
||||
[msg.userfront.dashboard.scopes]
|
||||
empty = "No scopes were requested."
|
||||
|
||||
[msg.userfront.dashboard.timeline]
|
||||
load_error = "Could not load sign-in history."
|
||||
|
||||
[msg.userfront.error]
|
||||
detail_contact = "If the problem continues, please contact your administrator."
|
||||
detail_generic = "Something went wrong."
|
||||
detail_request = "We had trouble processing your request."
|
||||
id = "Error ID: {id}"
|
||||
title = "An error occurred during authentication."
|
||||
title_generic = "An error occurred."
|
||||
title_with_code = "Error: {code}"
|
||||
type = "Error type: {type}"
|
||||
|
||||
[msg.userfront.error.tenant]
|
||||
account = "Account"
|
||||
account_unknown = "Unknown"
|
||||
affiliated_tenants = "All affiliated tenants"
|
||||
allowed_box_title = "Allowed tenants"
|
||||
allowed_tenants = "Allowed tenants"
|
||||
detail = "The currently signed-in account cannot access this application."
|
||||
load_failed = "We could not confirm the account details. Please try again."
|
||||
loading = "Loading the current account details."
|
||||
lookup_fallback = "Some fields could not be verified because the access context was incomplete."
|
||||
page_title = "Access to this application is restricted"
|
||||
primary_tenant = "Primary affiliated tenant"
|
||||
tenant = "Tenant"
|
||||
tenant_unknown = "Unknown"
|
||||
title = "Access restriction details"
|
||||
|
||||
[msg.userfront.error.ory]
|
||||
"$normalizedCode" = "{error}"
|
||||
access_denied = "The user denied the consent request."
|
||||
consent_required = "Consent is required to continue."
|
||||
interaction_required = "Additional interaction is required. Please try again."
|
||||
invalid_client = "Client authentication failed."
|
||||
invalid_grant = "The authorization grant is invalid or expired."
|
||||
invalid_request = "The request is invalid."
|
||||
invalid_scope = "The requested scope is invalid."
|
||||
login_required = "Login is required."
|
||||
request_forbidden = "The request was forbidden."
|
||||
server_error = "An authentication server error occurred."
|
||||
temporarily_unavailable = "The authentication server is temporarily unavailable."
|
||||
unauthorized_client = "The client is not authorized for this request."
|
||||
unsupported_response_type = "The response type is not supported."
|
||||
|
||||
[msg.userfront.error.whitelist]
|
||||
"$normalizedCode" = "{error}"
|
||||
bad_request = "Please check your input."
|
||||
invalid_session = "Your session has expired. Please sign in again."
|
||||
not_found = "The requested page could not be found."
|
||||
password_or_email_mismatch = "Email or password does not match."
|
||||
rate_limited = "Too many requests. Please try again later."
|
||||
recovery_expired = "The recovery link has expired. Please request a new one."
|
||||
recovery_invalid = "The recovery link is invalid."
|
||||
settings_disabled = "Account settings are currently unavailable."
|
||||
verification_required = "Additional verification is required. Please follow the instructions."
|
||||
|
||||
[msg.userfront.forgot]
|
||||
description = "Enter the email address or phone number linked to your account and we will send you a password reset link."
|
||||
dry_send = "Dry-send mode: no email or SMS was actually sent."
|
||||
error = "Failed to send the reset link: {error}"
|
||||
input_required = "Enter your email address or phone number."
|
||||
sent = "A password reset link has been sent. Check your email or SMS."
|
||||
|
||||
[msg.userfront.login]
|
||||
cookie_check_failed = "Could not verify your sign-in state: {error}"
|
||||
dry_send = "Dry-send mode: no email or SMS was actually sent."
|
||||
link_failed = "Could not complete link sign-in: {error}"
|
||||
link_send_failed = "Failed to send the sign-in link: {error}"
|
||||
link_sent_email = "We sent a sign-in link to your email address."
|
||||
link_sent_phone = "We sent a sign-in link to your phone number."
|
||||
link_timeout = "Time expired."
|
||||
no_account = "New to Baron?"
|
||||
oidc_failed = "OIDC sign-in failed. Please try again."
|
||||
qr_expired = "Time expired."
|
||||
qr_init_failed = "Failed to initialize QR sign-in: {error}"
|
||||
qr_login_required = "You need to be signed in to approve a QR sign-in."
|
||||
token_missing = "Could not find the sign-in token."
|
||||
verification_failed = "Failed to approve the sign-in request: {error}"
|
||||
|
||||
[msg.userfront.login.link]
|
||||
approved = "Sign-in approved. You will be redirected to the sign-in page shortly."
|
||||
helper = "We will send a sign-in link using the information you enter."
|
||||
missing_login_id = "Enter your email address or phone number."
|
||||
missing_phone = "Enter your phone number."
|
||||
resend_wait = "You can resend in {time}."
|
||||
short_code_help = "You can also sign in with the last 2 letters and 6 digits from the link you received."
|
||||
|
||||
[msg.userfront.login.password]
|
||||
failed = "Sign-in failed: {error}"
|
||||
missing_credentials = "Enter both your email or phone number and your password."
|
||||
|
||||
[msg.userfront.login.qr]
|
||||
load_failed = "Could not load the QR code."
|
||||
scan_hint = "Scan it with the mobile app."
|
||||
|
||||
[msg.userfront.login.short_code]
|
||||
invalid = "Enter the 2 letters and 6 digits from your code."
|
||||
|
||||
[msg.userfront.login.unregistered]
|
||||
body = "We could not find an account for that information.\\\\\\\\\\\\\\\\nPlease sign up before continuing."
|
||||
|
||||
[msg.userfront.login.verification]
|
||||
approved = "Approved. Complete sign-in in the original window."
|
||||
approved_local = "Approved. This device is already signed in, and the remote window will be signed in shortly."
|
||||
approved_remote = "Your requested sign-in is complete."
|
||||
pending_remote = "Checking the sign-in approval request. Please wait."
|
||||
close_hint = "You can close this window now."
|
||||
success = "Sign-in approval completed."
|
||||
|
||||
[msg.userfront.login_success]
|
||||
subtitle = "You have signed in successfully."
|
||||
|
||||
[msg.userfront.profile]
|
||||
department_missing = "No department information"
|
||||
department_required = "Enter your department."
|
||||
email_missing = "No email address"
|
||||
greeting = "Hello, {name}."
|
||||
load_failed = "Could not load your profile."
|
||||
name_missing = "No name provided"
|
||||
name_required = "Enter your name."
|
||||
phone_required = "Enter your phone number."
|
||||
phone_verify_required = "Phone verification is required."
|
||||
update_failed = "Failed to update your profile: {error}"
|
||||
update_success = "Your profile has been updated."
|
||||
|
||||
[msg.userfront.profile.password]
|
||||
change_failed = "Failed to change your password: {error}"
|
||||
changed = "Your password has been changed."
|
||||
current_required = "Enter your current password."
|
||||
mismatch = "The new passwords do not match."
|
||||
new_required = "Enter a new password."
|
||||
subtitle = "Verify your current password before setting a new one."
|
||||
|
||||
[msg.userfront.profile.phone]
|
||||
code_sent = "A verification code has been sent."
|
||||
send_failed = "Failed to send the code: {error}"
|
||||
verified = "Phone number verified."
|
||||
verify_failed = "Verification failed: {error}"
|
||||
verify_notice = "SMS verification is required to change your phone number."
|
||||
|
||||
[msg.userfront.profile.section]
|
||||
basic = "Manage your basic account information."
|
||||
organization = "Your organization and affiliation details."
|
||||
security = "Keep your password secure."
|
||||
|
||||
[msg.userfront.qr]
|
||||
approve_error = "QR approval failed: {error}"
|
||||
approve_success = "QR approval complete. Continue on your desktop."
|
||||
camera_error = "Camera error: {error}"
|
||||
permission_error = "Could not request camera access. Check your browser or OS settings."
|
||||
permission_required = "Camera access is required."
|
||||
|
||||
[msg.userfront.reset]
|
||||
invalid_body = "This password reset link is invalid or has expired. Please request a new one."
|
||||
invalid_link = "This reset link is invalid. Missing loginId or token."
|
||||
invalid_title = "Invalid reset link"
|
||||
policy_loading = "Loading the password policy..."
|
||||
success = "Your password has been changed successfully. Please sign in again."
|
||||
|
||||
[msg.userfront.reset.error]
|
||||
empty_password = "Please enter Password."
|
||||
generic = "Failed to change your password: {error}"
|
||||
lowercase = "Include at least one lowercase letter."
|
||||
min_length = "Use at least {count} characters."
|
||||
min_types = "Use at least {count} character types: uppercase, lowercase, number, or symbol."
|
||||
mismatch = "The passwords do not match."
|
||||
number = "Include at least one number."
|
||||
symbol = "Include at least one symbol."
|
||||
uppercase = "Include at least one uppercase letter."
|
||||
|
||||
[msg.userfront.reset.policy]
|
||||
lowercase = "At least one lowercase letter"
|
||||
min_length = "At least {count} characters"
|
||||
min_types = "At least {count} character types"
|
||||
number = "At least one number"
|
||||
symbol = "At least one symbol"
|
||||
uppercase = "At least one uppercase letter"
|
||||
|
||||
[msg.userfront.sections]
|
||||
apps_subtitle = "Your linked apps and their latest sign-in status."
|
||||
audit_subtitle = "Recent access history for Baron sign-in."
|
||||
sessions_subtitle = "Your currently signed-in devices and browser sessions."
|
||||
|
||||
[msg.userfront.settings]
|
||||
disabled = "Account settings are currently unavailable."
|
||||
|
||||
[msg.userfront.signup]
|
||||
failed = "Failed"
|
||||
privacy_full = "Privacy collection and use consent notice."
|
||||
tos_full = "Service terms of use notice."
|
||||
|
||||
[msg.userfront.signup.agreement]
|
||||
all_hint = "Agree to both required documents to continue to the next step."
|
||||
description = "Review the service terms and privacy collection notice, then agree to continue."
|
||||
privacy_summary = "Review what personal data is collected, why it is used, and how it is retained."
|
||||
progress = "{count} of {total} required agreements completed"
|
||||
title = "Please review and agree to the terms to continue."
|
||||
tos_summary = "Review the service terms, usage conditions, and responsibilities."
|
||||
|
||||
[msg.userfront.signup.auth]
|
||||
affiliate_notice = "If you are an affiliate employee, use your official company email address."
|
||||
title = "Verify your email and phone number."
|
||||
|
||||
[msg.userfront.signup.email]
|
||||
code_mismatch = "The verification code does not match."
|
||||
duplicate = "This email address is already registered."
|
||||
invalid = "Enter a valid email address."
|
||||
send_failed = "Failed to send the email: {error}"
|
||||
verified = "Email verified."
|
||||
verify_failed = "Email verification failed: {error}"
|
||||
|
||||
[msg.userfront.signup.password]
|
||||
length_required = "Your password must be at least 12 characters long."
|
||||
lowercase_required = "Include at least one lowercase letter."
|
||||
mismatch = "The passwords do not match."
|
||||
number_required = "Include at least one number."
|
||||
symbol_required = "Include at least one symbol."
|
||||
title = "Create a secure password to finish signing up."
|
||||
uppercase_required = "Include at least one uppercase letter."
|
||||
|
||||
[msg.userfront.signup.password.rule]
|
||||
lowercase = "Lowercase letter"
|
||||
min_length = "At least {count} characters"
|
||||
min_types = "At least {count} character types"
|
||||
number = "Number"
|
||||
symbol = "Symbol"
|
||||
uppercase = "Uppercase letter"
|
||||
|
||||
[msg.userfront.signup.phone]
|
||||
code_mismatch = "The verification code does not match."
|
||||
send_failed = "Failed to send the SMS: {error}"
|
||||
verified = "Phone number verified."
|
||||
verify_failed = "Phone verification failed: {error}"
|
||||
|
||||
[msg.userfront.signup.policy]
|
||||
loading = "Loading the password policy..."
|
||||
lowercase = "Lowercase letter"
|
||||
min_length = "At least {count} characters"
|
||||
min_types = "At least {count} character types"
|
||||
number = "Number"
|
||||
summary = "Security policy: {rules}"
|
||||
symbol = "Symbol"
|
||||
uppercase = "Uppercase letter"
|
||||
|
||||
[msg.userfront.signup.profile]
|
||||
affiliate_hint = "This will be selected automatically when you use an affiliate email."
|
||||
title = "Tell us about your affiliation."
|
||||
|
||||
[msg.userfront.signup.success]
|
||||
body = "Your account has been created successfully."
|
||||
title = "Sign-up complete"
|
||||
|
||||
[ui.common]
|
||||
add = "Add"
|
||||
admin_only = "Admin Only"
|
||||
all = "All"
|
||||
assign = "Assign"
|
||||
back = "Back"
|
||||
back_to_login = "Back to login"
|
||||
cancel = "Cancel"
|
||||
change_file = "Change File"
|
||||
clear_search = "Clear Search"
|
||||
close = "Close"
|
||||
collapse = "Collapse"
|
||||
confirm = "Confirm"
|
||||
copy = "Copy"
|
||||
create = "Create"
|
||||
delete = "Delete"
|
||||
details = "Details"
|
||||
edit = "Edit"
|
||||
enabled = "Enabled"
|
||||
export = "Export"
|
||||
fail = "Fail"
|
||||
generate = "ui.common.generate"
|
||||
go_home = "Go Home"
|
||||
hyphen = "-"
|
||||
language = "Language"
|
||||
language_en = "English"
|
||||
language_ko = "Korean"
|
||||
manage = "Manage"
|
||||
na = "N/A"
|
||||
never = "Never"
|
||||
next = "Next"
|
||||
none = "None"
|
||||
page_of = "Page {page} of {total}"
|
||||
prev = "Prev"
|
||||
previous = "Previous"
|
||||
qr = "QR"
|
||||
read_only = "Read Only"
|
||||
refresh = "Refresh"
|
||||
remove = "Remove"
|
||||
resend = "Resend"
|
||||
reset = "Reset"
|
||||
retry = "Retry"
|
||||
save = "Save"
|
||||
search = "Search"
|
||||
select = "Select"
|
||||
select_file = "Select File"
|
||||
select_placeholder = "Select Placeholder"
|
||||
show_more = "Show More"
|
||||
success = "Success"
|
||||
theme_dark = "Dark"
|
||||
theme_light = "Light"
|
||||
theme_toggle = "Theme Toggle"
|
||||
unknown = "Unknown"
|
||||
view = "View"
|
||||
|
||||
[ui.common.badge]
|
||||
admin_only = "Admin only"
|
||||
command_only = "Command only"
|
||||
system = "System"
|
||||
|
||||
[ui.common.status]
|
||||
active = "Active"
|
||||
archived = "Archived"
|
||||
baron_guest = "Baron Guest"
|
||||
blocked = "ui.common.status.blocked"
|
||||
extended_leave = "Extended Leave"
|
||||
failure = "Failure"
|
||||
inactive = "Inactive"
|
||||
leave_of_absence = "Leave of absence"
|
||||
ok = "Ok"
|
||||
pending = "Pending"
|
||||
preboarding = "Preboarding"
|
||||
success = "Success"
|
||||
suspended = "Suspended"
|
||||
temporary_leave = "Temporary Leave"
|
||||
|
||||
[ui.userfront]
|
||||
app_title = "Baron SW Portal"
|
||||
|
||||
[ui.userfront.app_label]
|
||||
admin_console = "Admin Console"
|
||||
baron = "Baron"
|
||||
dev_console = "Dev Console"
|
||||
|
||||
[ui.userfront.audit]
|
||||
|
||||
[ui.userfront.audit.table]
|
||||
action = "Action"
|
||||
app = "App"
|
||||
auth_method = "Auth Method"
|
||||
browser = "Browser"
|
||||
date = "Date"
|
||||
device = "Device"
|
||||
ip = "IP"
|
||||
pending = "Pending"
|
||||
result = "Result"
|
||||
session_id = "Session ID"
|
||||
status = "Status"
|
||||
|
||||
[ui.userfront.auth_method]
|
||||
ory = "Ory"
|
||||
session = "Session"
|
||||
|
||||
[ui.userfront.consent]
|
||||
accept = "Agree and continue"
|
||||
requested_scopes = "Requested permissions"
|
||||
title = "Permission request"
|
||||
|
||||
[ui.userfront.consent.cancel]
|
||||
confirm_button = "Yes, cancel"
|
||||
title = "Cancel consent"
|
||||
|
||||
[ui.userfront.dashboard]
|
||||
last_auth_label = "Last sign-in"
|
||||
link_status_label = "Link status"
|
||||
status_history = "Link details"
|
||||
|
||||
[ui.userfront.dashboard.activity]
|
||||
linked = "Linked"
|
||||
|
||||
[ui.userfront.dashboard.sessions]
|
||||
active_badge = "Active"
|
||||
current_badge = "Current"
|
||||
current_disabled = "Current session"
|
||||
unknown_device = "Unknown device"
|
||||
unknown_session = "Session"
|
||||
|
||||
[ui.userfront.dashboard.sessions.revoke]
|
||||
action = "End session"
|
||||
title = "End session"
|
||||
|
||||
[ui.userfront.dashboard.approved_session]
|
||||
default = "Default"
|
||||
userfront = "Approved UserFront session ID"
|
||||
|
||||
[ui.userfront.dashboard.revoke]
|
||||
confirm_button = "Disconnect"
|
||||
title = "Disconnect app"
|
||||
|
||||
[ui.userfront.dashboard.scopes]
|
||||
title = "Consent scopes"
|
||||
|
||||
[ui.userfront.dashboard.status]
|
||||
revoked = "Revoked"
|
||||
|
||||
[ui.userfront.device]
|
||||
android = "Mobile(Android)"
|
||||
ios = "Mobile(iOS)"
|
||||
linux = "Desktop(Linux)"
|
||||
macos = "Desktop(macOS)"
|
||||
windows = "Desktop(Windows)"
|
||||
|
||||
[ui.userfront.error]
|
||||
go_home = "Go Home"
|
||||
go_login = "Go Login"
|
||||
switch_account = "Sign in with another account"
|
||||
|
||||
[ui.userfront.forgot]
|
||||
heading = "Forgot your password?"
|
||||
input_label = "Email address or phone number"
|
||||
submit = "Send reset link"
|
||||
title = "Reset password"
|
||||
|
||||
[ui.userfront.login]
|
||||
forgot_password = "Forgot Password"
|
||||
signup = "Sign up"
|
||||
|
||||
[ui.userfront.login.action]
|
||||
submit = "Sign in"
|
||||
|
||||
[ui.userfront.login.field]
|
||||
login_id = "Email address or phone number"
|
||||
password = "Password"
|
||||
|
||||
[ui.userfront.login.link]
|
||||
action_label = "Go to sign-in"
|
||||
code_only = "Get code only ({time})"
|
||||
page_title = "Link sign-in"
|
||||
resend_with_time = "Resend ({time})"
|
||||
send = "Send"
|
||||
title = "Link sign-in complete"
|
||||
|
||||
[ui.userfront.login.qr]
|
||||
expired = "Expired"
|
||||
refresh = "Refresh"
|
||||
remaining = "Remaining: {time}"
|
||||
|
||||
[ui.userfront.login.short_code]
|
||||
digits = "6 digits"
|
||||
expire_time = "Expires in {time}"
|
||||
prefix = "2 letters"
|
||||
submit = "Sign in with code"
|
||||
|
||||
[ui.userfront.login.tabs]
|
||||
link = "Sign-in link"
|
||||
password = "Password"
|
||||
qr = "QR Code"
|
||||
|
||||
[ui.userfront.login.unregistered]
|
||||
action = "Create an account"
|
||||
title = "Account not found"
|
||||
|
||||
[ui.userfront.login.verification]
|
||||
action_label = "Done"
|
||||
action_label_remote = "Go to sign-in window"
|
||||
action_label_close = "Close Window"
|
||||
page_title = "Baron SW Portal"
|
||||
title = "Approval complete"
|
||||
title_pending = "Checking approval"
|
||||
title_remote = "Sign-in Approved"
|
||||
|
||||
[ui.userfront.login_success]
|
||||
later = "Do this later (go to dashboard)"
|
||||
qr = "Use QR approval"
|
||||
title = "Sign-in complete"
|
||||
|
||||
[ui.userfront.nav]
|
||||
dashboard = "Dashboard"
|
||||
logout = "Logout"
|
||||
profile = "Profile"
|
||||
qr_scan = "QR Scan"
|
||||
|
||||
[ui.userfront.profile]
|
||||
department_empty = "Department Empty"
|
||||
manage = "Manage profile"
|
||||
user_fallback = "User"
|
||||
|
||||
[ui.userfront.profile.field]
|
||||
affiliation = "Affiliation"
|
||||
company_code = "Company Code"
|
||||
department = "Department"
|
||||
email = "Email"
|
||||
name = "Name"
|
||||
tenant = "Tenant"
|
||||
tenant_slug = "Tenant Slug"
|
||||
|
||||
[ui.userfront.profile.password]
|
||||
change = "Change"
|
||||
confirm = "Confirm"
|
||||
current = "Current"
|
||||
forgot = "Forgot"
|
||||
new = "New"
|
||||
title = "Change password"
|
||||
|
||||
[ui.userfront.profile.phone]
|
||||
code_hint = "6-digit code"
|
||||
request_code = "Send code"
|
||||
title = "Phone number"
|
||||
|
||||
[ui.userfront.profile.section]
|
||||
basic = "Basic"
|
||||
organization = "Organization"
|
||||
security = "Security"
|
||||
|
||||
[ui.userfront.qr]
|
||||
request_permission = "Allow camera access"
|
||||
rescan = "Rescan"
|
||||
result_failure = "Approval failed"
|
||||
result_success = "Approval complete"
|
||||
title = "Scan QR Code"
|
||||
|
||||
[ui.userfront.reset]
|
||||
confirm_password = "Confirm Password"
|
||||
new_password = "New Password"
|
||||
submit = "Submit"
|
||||
subtitle = "Set a new password"
|
||||
title = "Create a new password"
|
||||
|
||||
[ui.userfront.sections]
|
||||
apps = "Apps"
|
||||
audit = "Audit"
|
||||
sessions = "Sessions"
|
||||
|
||||
[ui.userfront.session]
|
||||
active = "Active session"
|
||||
unknown = "Unknown"
|
||||
|
||||
[ui.userfront.signup]
|
||||
complete = "Finish sign-up"
|
||||
next_step = "Next"
|
||||
title = "Sign up"
|
||||
|
||||
[ui.userfront.signup.agreement]
|
||||
all = "Agree to all"
|
||||
privacy_title = "Privacy Policy (Required)"
|
||||
required = "Required"
|
||||
tos_title = "Terms of Service (Required)"
|
||||
|
||||
[ui.userfront.signup.auth]
|
||||
code_label = "6-digit verification code"
|
||||
request_code = "Send code"
|
||||
|
||||
[ui.userfront.signup.auth.email]
|
||||
label = "Email address"
|
||||
title = "Email verification"
|
||||
|
||||
[ui.userfront.signup.password]
|
||||
confirm_label = "Password Confirm"
|
||||
label = "Password"
|
||||
|
||||
[ui.userfront.signup.phone]
|
||||
label = "Phone number (no hyphens)"
|
||||
title = "Phone verification"
|
||||
|
||||
[ui.userfront.signup.profile]
|
||||
affiliation_type = "Affiliation Type"
|
||||
company = "Company"
|
||||
department = "Department"
|
||||
department_optional = "Department (optional)"
|
||||
name = "Name"
|
||||
|
||||
[ui.userfront.signup.steps]
|
||||
agreement = "Terms"
|
||||
password = "Password"
|
||||
profile = "Profile"
|
||||
verify = "Verification"
|
||||
|
||||
[ui.userfront.signup.success]
|
||||
action = "Go to sign-in"
|
||||
|
||||
|
||||
[ui.userfront.audit.filter]
|
||||
title = "Manage My Activity"
|
||||
toggle_label = "Show active sessions only"
|
||||
|
||||
[msg.userfront.audit.filter]
|
||||
description = "Toggle to view only active sessions."
|
||||
|
||||
930
baron-sso/userfront/assets/translations/ko.toml
Normal file
@@ -0,0 +1,930 @@
|
||||
[domain]
|
||||
|
||||
[domain.affiliation]
|
||||
affiliate = "가족사 임직원"
|
||||
general = "일반 사용자"
|
||||
|
||||
[domain.company]
|
||||
baron = "바론"
|
||||
halla = "한라"
|
||||
hanmac = "한맥"
|
||||
jangheon = "장헌"
|
||||
ptc = "PTC"
|
||||
saman = "삼안"
|
||||
|
||||
[domain.tenant_type]
|
||||
company = "COMPANY (일반 기업)"
|
||||
company_group = "COMPANY_GROUP (그룹사/지주사)"
|
||||
organization = "ORGANIZATION (정규 조직)"
|
||||
personal = "PERSONAL (개인 워크스페이스)"
|
||||
user_group = "USER_GROUP (내부 부서/팀)"
|
||||
|
||||
[err.userfront]
|
||||
|
||||
[err.userfront.auth_proxy]
|
||||
consent_accept = "동의 처리에 실패했습니다."
|
||||
consent_fetch = "동의 정보를 가져오지 못했습니다."
|
||||
consent_reject = "동의 거부에 실패했습니다."
|
||||
linked_app_revoke = "연동 해지에 실패했습니다."
|
||||
login_failed = "로그인에 실패했습니다."
|
||||
oidc_accept = "OIDC 로그인 승인에 실패했습니다."
|
||||
password_reset_complete = "비밀번호 재설정에 실패했습니다."
|
||||
password_reset_init = "비밀번호 재설정을 시작하지 못했습니다."
|
||||
|
||||
[err.userfront.profile]
|
||||
load_failed = "프로필을 불러오지 못했습니다: {error}"
|
||||
password_change_failed = "비밀번호 변경에 실패했습니다: {error}"
|
||||
send_code_failed = "인증번호 전송 실패: {error}"
|
||||
update_failed = "프로필 업데이트에 실패했습니다: {error}"
|
||||
verify_code_failed = "인증 실패: {error}"
|
||||
|
||||
[err.userfront.session]
|
||||
missing = "활성 세션이 없습니다."
|
||||
|
||||
[msg.userfront.audit]
|
||||
browser = "브라우저: {value}"
|
||||
date = "접속일자: {value}"
|
||||
device = "접속환경: {value}"
|
||||
end = "더 이상 항목이 없습니다."
|
||||
filtered_empty = "활성 세션으로 필터링된 접속 이력이 없습니다."
|
||||
ip = "접속 IP: {value}"
|
||||
load_more_error = "더 불러오지 못했습니다."
|
||||
result = "인증결과: {value}"
|
||||
session_id = "Session ID: {value}"
|
||||
status = "현황: (준비중)"
|
||||
|
||||
[msg.userfront.dashboard]
|
||||
approved_device = "승인 기기: {device}"
|
||||
approved_ip = "승인 IP: {ip}"
|
||||
audit_empty = "최근 접속 이력이 없습니다."
|
||||
audit_load_error = "접속이력을 불러오지 못했습니다."
|
||||
auth_method = "인증수단: {method}"
|
||||
client_id = "Client ID: {id}"
|
||||
client_id_missing = "Client ID 없음"
|
||||
current_status = "현재 상태: {status}"
|
||||
last_auth = "최근 인증: {value}"
|
||||
link_status = "연동 상태: {status}"
|
||||
link_missing = "이동할 페이지 주소(Client URI)가 설정되지 않았습니다."
|
||||
link_open_error = "해당 링크를 열 수 없습니다."
|
||||
render_error = "대시보드 렌더링 오류: {error}"
|
||||
session_id_copied = "세션 ID가 복사되었습니다."
|
||||
|
||||
[msg.userfront.error]
|
||||
detail_contact = "관리자에게 문의해 주세요."
|
||||
detail_generic = "오류가 발생했습니다."
|
||||
detail_request = "요청을 처리하는 중 문제가 발생했습니다."
|
||||
id = "오류 ID: {id}"
|
||||
title = "인증 과정에서 오류가 발생했습니다"
|
||||
title_generic = "오류가 발생했습니다"
|
||||
title_with_code = "오류: {code}"
|
||||
type = "오류 종류: {type}"
|
||||
|
||||
[msg.userfront.error.tenant]
|
||||
account = "계정"
|
||||
account_unknown = "알 수 없음"
|
||||
affiliated_tenants = "전체 소속 테넌트"
|
||||
allowed_box_title = "접속 가능 테넌트"
|
||||
allowed_tenants = "접속 가능 테넌트"
|
||||
detail = "현재 로그인된 계정은 이 애플리케이션에 접근할 수 없습니다."
|
||||
load_failed = "계정 정보를 확인하지 못했습니다. 다시 시도해 주세요."
|
||||
loading = "현재 계정 정보를 불러오는 중입니다."
|
||||
lookup_fallback = "표시 정보가 충분하지 않아 일부 항목은 확인되지 않을 수 있습니다."
|
||||
page_title = "애플리케이션 접근이 제한되었습니다"
|
||||
primary_tenant = "대표 소속 테넌트"
|
||||
tenant = "소속 테넌트"
|
||||
tenant_unknown = "알 수 없음"
|
||||
title = "접근 제한 정보"
|
||||
|
||||
[msg.userfront.forgot]
|
||||
description = "계정과 연결된 이메일 주소 또는 휴대폰 번호를 입력하시면, 비밀번호를 재설정할 수 있는 링크를 보내드립니다."
|
||||
dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다."
|
||||
error = "전송에 실패했습니다: {error}"
|
||||
input_required = "이메일 또는 휴대폰 번호를 입력해주세요."
|
||||
sent = "비밀번호 재설정 링크가 전송되었습니다. 이메일 또는 SMS를 확인해주세요."
|
||||
|
||||
[msg.userfront.login]
|
||||
cookie_check_failed = "로그인 확인 실패: {error}"
|
||||
dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다."
|
||||
link_failed = "오류: {error}"
|
||||
link_send_failed = "전송 실패: {error}"
|
||||
link_sent_email = "입력하신 이메일로 로그인 링크를 보냈습니다."
|
||||
link_sent_phone = "입력하신 번호로 로그인 링크를 보냈습니다."
|
||||
link_timeout = "시간이 경과되었습니다."
|
||||
no_account = "계정이 없으신가요?"
|
||||
oidc_failed = "OIDC 로그인 처리에 실패했습니다. 다시 시도해 주세요."
|
||||
qr_expired = "시간이 경과되었습니다."
|
||||
qr_init_failed = "QR 초기화에 실패했습니다: {error}"
|
||||
qr_login_required = "로그인 한 상태여야 QR 스캔으로 로그인 할 수 있습니다"
|
||||
token_missing = "로그인 토큰을 확인할 수 없습니다."
|
||||
verification_failed = "승인 처리에 실패했습니다: {error}"
|
||||
|
||||
[msg.userfront.login_success]
|
||||
subtitle = "성공적으로 로그인되었습니다."
|
||||
|
||||
[msg.userfront.consent]
|
||||
accept_error = "동의 처리에 실패했습니다: {error}"
|
||||
client_id = "클라이언트 ID: {id}"
|
||||
client_unknown = "알 수 없는 앱"
|
||||
description = "아래 서비스가 회원님의 계정 정보에 접근하려고 합니다.\n계속 진행하려면 동의 여부를 선택해 주세요."
|
||||
load_error = "동의 정보를 불러오는데 실패했습니다: {error}"
|
||||
missing_redirect = "동의가 처리되었으나 리다이렉트 URL을 받지 못했습니다."
|
||||
redirect_notice = "동의 후 자동으로 서비스로 이동합니다."
|
||||
scope_count = "총 {count}개"
|
||||
|
||||
[msg.userfront.profile]
|
||||
department_missing = "소속 정보 없음"
|
||||
department_required = "소속을 입력해주세요."
|
||||
email_missing = "이메일 없음"
|
||||
greeting = "안녕하세요, {name}님"
|
||||
load_failed = "정보를 불러올 수 없습니다."
|
||||
name_missing = "이름 없음"
|
||||
name_required = "이름을 입력해주세요."
|
||||
phone_required = "휴대폰 번호를 입력해주세요."
|
||||
phone_verify_required = "휴대폰 번호 인증이 필요합니다."
|
||||
update_failed = "수정 실패: {error}"
|
||||
update_success = "정보가 수정되었습니다."
|
||||
|
||||
[msg.userfront.qr]
|
||||
camera_error = "카메라 오류: {error}"
|
||||
permission_error = "카메라 권한 요청에 실패했습니다. 브라우저/OS 설정을 확인해주세요."
|
||||
permission_required = "카메라 권한이 필요합니다."
|
||||
|
||||
[msg.userfront.reset]
|
||||
invalid_body = "비밀번호 재설정 링크가 만료되었거나 잘못되었습니다. 다시 시도해주세요."
|
||||
invalid_link = "유효하지 않은 재설정 링크입니다. (loginId/token 누락)"
|
||||
invalid_title = "유효하지 않은 링크입니다."
|
||||
policy_loading = "비밀번호 정책을 불러오는 중입니다..."
|
||||
success = "비밀번호가 성공적으로 변경되었습니다. 다시 로그인해주세요."
|
||||
|
||||
[msg.userfront.sections]
|
||||
apps_subtitle = "현재 연결된 앱과 최근 인증 상태입니다."
|
||||
audit_subtitle = "Baron 로그인 기준의 최근 접근 기록입니다."
|
||||
sessions_subtitle = "현재 로그인된 기기와 브라우저 세션입니다."
|
||||
|
||||
[msg.userfront.settings]
|
||||
disabled = "현재 계정 설정 화면은 준비 중입니다."
|
||||
|
||||
[msg.userfront.signup]
|
||||
failed = "가입 실패: {error}"
|
||||
privacy_full = "개인정보 수집 및 이용 동의 전문..."
|
||||
tos_full = "서비스 이용약관 전문..."
|
||||
|
||||
[ui.common.badge]
|
||||
admin_only = "Admin only"
|
||||
command_only = "Command only"
|
||||
system = "System"
|
||||
|
||||
[ui.common.status]
|
||||
active = "활성"
|
||||
blocked = "차단됨"
|
||||
failure = "실패"
|
||||
inactive = "비활성"
|
||||
ok = "정상"
|
||||
pending = "준비 중"
|
||||
success = "성공"
|
||||
|
||||
[ui.userfront.app_label]
|
||||
admin_console = "Admin Console"
|
||||
baron = "Baron 로그인"
|
||||
dev_console = "Dev Console"
|
||||
|
||||
[ui.userfront.auth_method]
|
||||
ory = "Ory 세션"
|
||||
session = "세션"
|
||||
|
||||
[ui.userfront.dashboard]
|
||||
last_auth_label = "최근 인증"
|
||||
link_status_label = "연동 상태"
|
||||
status_history = "연동 정보"
|
||||
|
||||
[ui.userfront.device]
|
||||
android = "Mobile(Android)"
|
||||
ios = "Mobile(iOS)"
|
||||
linux = "Desktop(Linux)"
|
||||
macos = "Desktop(macOS)"
|
||||
windows = "Desktop(Windows)"
|
||||
|
||||
[ui.userfront.error]
|
||||
go_home = "홈으로 이동"
|
||||
go_login = "로그인으로 이동"
|
||||
switch_account = "다른 계정으로 로그인"
|
||||
|
||||
[ui.userfront.forgot]
|
||||
heading = "비밀번호를 잊으셨나요?"
|
||||
input_label = "이메일 또는 휴대폰 번호"
|
||||
submit = "재설정 링크 전송"
|
||||
title = "비밀번호 재설정"
|
||||
|
||||
[ui.userfront.login]
|
||||
forgot_password = "비밀번호를 잊으셨나요?"
|
||||
signup = "회원가입"
|
||||
|
||||
[ui.userfront.login_success]
|
||||
later = "나중에 하기 (대시보드로 이동)"
|
||||
qr = "QR 인증 (카메라 켜기)"
|
||||
title = "로그인 완료"
|
||||
|
||||
[ui.userfront.consent]
|
||||
accept = "동의하고 계속하기"
|
||||
requested_scopes = "요청된 권한"
|
||||
title = "접근 권한 요청"
|
||||
|
||||
[ui.userfront.nav]
|
||||
dashboard = "대시보드"
|
||||
logout = "로그아웃"
|
||||
profile = "내 정보"
|
||||
qr_scan = "QR 스캔"
|
||||
|
||||
[ui.userfront.profile]
|
||||
department_empty = "소속 정보 없음"
|
||||
manage = "프로필 관리"
|
||||
user_fallback = "사용자"
|
||||
|
||||
[ui.userfront.qr]
|
||||
rescan = "다시 스캔"
|
||||
result_success = "승인 완료"
|
||||
title = "Scan QR Code"
|
||||
|
||||
[ui.userfront.reset]
|
||||
confirm_password = "새 비밀번호 확인"
|
||||
new_password = "새 비밀번호"
|
||||
submit = "비밀번호 변경"
|
||||
subtitle = "새로운 비밀번호 설정"
|
||||
title = "새 비밀번호 설정"
|
||||
|
||||
[ui.userfront.sections]
|
||||
apps = "나의 App 현황"
|
||||
audit = "접속이력"
|
||||
sessions = "활성 세션"
|
||||
|
||||
[ui.userfront.session]
|
||||
active = "세션 활성"
|
||||
unknown = "알 수 없음"
|
||||
|
||||
[ui.userfront.signup]
|
||||
complete = "가입 완료"
|
||||
next_step = "다음 단계"
|
||||
title = "회원가입"
|
||||
|
||||
[msg.userfront]
|
||||
greeting = "안녕하세요, {name}님"
|
||||
|
||||
[msg.userfront.audit]
|
||||
browser = "브라우저: {value}"
|
||||
date = "접속일자: {value}"
|
||||
device = "접속환경: {value}"
|
||||
end = "더 이상 항목이 없습니다."
|
||||
filtered_empty = "활성 세션으로 필터링된 접속 이력이 없습니다."
|
||||
ip = "접속 IP: {value}"
|
||||
load_more_error = "더 불러오지 못했습니다."
|
||||
result = "인증결과: {value}"
|
||||
session_id = "Session ID: {value}"
|
||||
status = "현황: (준비중)"
|
||||
|
||||
[msg.userfront.consent]
|
||||
accept_error = "동의 처리에 실패했습니다: {error}"
|
||||
client_id = "클라이언트 ID: {id}"
|
||||
client_unknown = "알 수 없는 앱"
|
||||
description = "아래 서비스가 회원님의 계정 정보에 접근하려고 합니다.\\\\n계속 진행하려면 동의 여부를 선택해 주세요."
|
||||
load_error = "동의 정보를 불러오는데 실패했습니다: {error}"
|
||||
missing_redirect = "동의가 처리되었으나 리다이렉트 URL을 받지 못했습니다."
|
||||
redirect_notice = "동의 후 자동으로 서비스로 이동합니다."
|
||||
scope_count = "총 {count}개"
|
||||
|
||||
[msg.userfront.consent.cancel]
|
||||
confirm = "권한 동의를 취소하면 해당 서비스를 이용할 수 없습니다. 취소하시겠습니까?"
|
||||
error = "취소 처리 중 오류가 발생했습니다: {error}"
|
||||
|
||||
[msg.userfront.consent.scope]
|
||||
email = "이메일 주소 (계정 식별 및 알림 용도)"
|
||||
offline_access = "오프라인 접근 (로그인 유지)"
|
||||
openid = "OpenID 인증 정보 (로그인 상태 확인)"
|
||||
phone = "휴대폰 번호 (본인 인증 및 알림)"
|
||||
profile = "기본 프로필 정보 (이름, 사용자 식별자)"
|
||||
|
||||
[msg.userfront.dashboard]
|
||||
approved_device = "승인 기기: {device}"
|
||||
approved_ip = "승인 IP: {ip}"
|
||||
audit_empty = "최근 접속 이력이 없습니다."
|
||||
audit_load_error = "접속이력을 불러오지 못했습니다."
|
||||
auto_login_supported = "연동앱 클릭 시 별도 로그인 없이 로그인할 수 있습니다."
|
||||
auth_method = "인증수단: {method}"
|
||||
client_id = "Client ID: {id}"
|
||||
client_id_missing = "Client ID 없음"
|
||||
current_status = "현재 상태: {status}"
|
||||
last_auth = "최근 인증: {value}"
|
||||
link_missing = "이동할 페이지 주소(Client URI)가 설정되지 않았습니다."
|
||||
link_open_error = "해당 링크를 열 수 없습니다."
|
||||
render_error = "대시보드 렌더링 오류: {error}"
|
||||
session_id_copied = "세션 ID가 복사되었습니다."
|
||||
|
||||
[msg.userfront.dashboard.activities]
|
||||
empty = "연동된 앱이 없습니다."
|
||||
empty_detail = "앱을 연동하면 최근 활동과 상태가 표시됩니다."
|
||||
error = "연동 정보를 불러오지 못했습니다."
|
||||
|
||||
[msg.userfront.dashboard.sessions]
|
||||
browser = "브라우저: {value}"
|
||||
empty = "활성 세션이 없습니다."
|
||||
empty_detail = "같은 계정으로 로그인한 기기가 여기에 표시됩니다."
|
||||
error = "세션 정보를 불러오지 못했습니다."
|
||||
os = "OS: {value}"
|
||||
recent_app = "최근 접속 앱: {app}"
|
||||
session_id = "세션 ID: {id}"
|
||||
|
||||
[msg.userfront.dashboard.sessions.revoke]
|
||||
confirm = "{target} 세션을 종료하시겠습니까?\n대상 기기에서는 다시 로그인이 필요합니다."
|
||||
error = "세션 종료 실패: {error}"
|
||||
success = "세션이 종료되었습니다."
|
||||
|
||||
[msg.userfront.dashboard.approved_session]
|
||||
copy_click = "{label}: {id}\\\\n클릭하면 복사됩니다."
|
||||
copy_tap = "{label}: {id}\\\\n탭하면 복사됩니다."
|
||||
none = "{label} 없음"
|
||||
|
||||
[msg.userfront.dashboard.revoke]
|
||||
confirm = "{app} 앱과의 연동을 해지하시겠습니까?\\\\n해지하면 다음 로그인 시 다시 동의가 필요합니다."
|
||||
error = "해지 실패: {error}"
|
||||
success = "{app} 연동이 해지되었습니다."
|
||||
|
||||
[msg.userfront.dashboard.scopes]
|
||||
empty = "요청된 권한이 없습니다."
|
||||
|
||||
[msg.userfront.dashboard.timeline]
|
||||
load_error = "접속이력을 불러오지 못했습니다."
|
||||
|
||||
[msg.userfront.error]
|
||||
detail_contact = "관리자에게 문의해 주세요."
|
||||
detail_generic = "오류가 발생했습니다."
|
||||
detail_request = "요청을 처리하는 중 문제가 발생했습니다."
|
||||
id = "오류 ID: {id}"
|
||||
title = "인증 과정에서 오류가 발생했습니다"
|
||||
title_generic = "오류가 발생했습니다"
|
||||
title_with_code = "오류: {code}"
|
||||
type = "오류 종류: {type}"
|
||||
|
||||
[msg.userfront.error.tenant]
|
||||
account = "계정"
|
||||
account_unknown = "알 수 없음"
|
||||
affiliated_tenants = "전체 소속 테넌트"
|
||||
allowed_box_title = "접속 가능 테넌트"
|
||||
allowed_tenants = "접속 가능 테넌트"
|
||||
detail = "현재 로그인된 계정은 이 애플리케이션에 접근할 수 없습니다."
|
||||
load_failed = "계정 정보를 확인하지 못했습니다. 다시 시도해 주세요."
|
||||
loading = "현재 계정 정보를 불러오는 중입니다."
|
||||
lookup_fallback = "표시 정보가 충분하지 않아 일부 항목은 확인되지 않을 수 있습니다."
|
||||
page_title = "애플리케이션 접근이 제한되었습니다"
|
||||
primary_tenant = "대표 소속 테넌트"
|
||||
tenant = "소속 테넌트"
|
||||
tenant_unknown = "알 수 없음"
|
||||
title = "접근 제한 정보"
|
||||
|
||||
[msg.userfront.error.ory]
|
||||
"$normalizedCode" = "{error}"
|
||||
access_denied = "사용자가 동의를 거부했습니다."
|
||||
consent_required = "앱 접근 동의가 필요합니다."
|
||||
interaction_required = "추가 상호작용이 필요합니다. 다시 시도해 주세요."
|
||||
invalid_client = "클라이언트 인증 정보가 유효하지 않습니다."
|
||||
invalid_grant = "인증 요청이 만료되었거나 유효하지 않습니다."
|
||||
invalid_request = "잘못된 요청입니다."
|
||||
invalid_scope = "요청한 권한 범위가 유효하지 않습니다."
|
||||
login_required = "로그인이 필요합니다."
|
||||
request_forbidden = "요청이 거부되었습니다."
|
||||
server_error = "인증 서버 오류가 발생했습니다."
|
||||
temporarily_unavailable = "인증 서버를 일시적으로 사용할 수 없습니다."
|
||||
unauthorized_client = "해당 클라이언트는 이 요청을 수행할 수 없습니다."
|
||||
unsupported_response_type = "지원하지 않는 응답 타입입니다."
|
||||
|
||||
[msg.userfront.error.whitelist]
|
||||
"$normalizedCode" = "{error}"
|
||||
bad_request = "입력값을 확인해 주세요."
|
||||
invalid_session = "세션이 만료되었습니다. 다시 로그인해 주세요."
|
||||
not_found = "요청한 페이지를 찾을 수 없습니다."
|
||||
password_or_email_mismatch = "이메일 혹은 비밀번호가 일치하지 않습니다."
|
||||
rate_limited = "요청이 많습니다. 잠시 후 다시 시도해 주세요."
|
||||
recovery_expired = "재설정 링크가 만료되었습니다. 다시 요청해 주세요."
|
||||
recovery_invalid = "재설정 링크가 유효하지 않습니다."
|
||||
settings_disabled = "현재 계정 설정 화면은 준비 중입니다."
|
||||
verification_required = "추가 인증이 필요합니다. 안내에 따라 진행해 주세요."
|
||||
|
||||
[msg.userfront.forgot]
|
||||
description = "계정과 연결된 이메일 주소 또는 휴대폰 번호를 입력하시면, 비밀번호를 재설정할 수 있는 링크를 보내드립니다."
|
||||
dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다."
|
||||
error = "전송에 실패했습니다: {error}"
|
||||
input_required = "이메일 또는 휴대폰 번호를 입력해주세요."
|
||||
sent = "비밀번호 재설정 링크가 전송되었습니다. 이메일 또는 SMS를 확인해주세요."
|
||||
|
||||
[msg.userfront.login]
|
||||
cookie_check_failed = "로그인 확인 실패: {error}"
|
||||
dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다."
|
||||
link_failed = "오류: {error}"
|
||||
link_send_failed = "전송 실패: {error}"
|
||||
link_sent_email = "입력하신 이메일로 로그인 링크를 보냈습니다."
|
||||
link_sent_phone = "입력하신 번호로 로그인 링크를 보냈습니다."
|
||||
link_timeout = "시간이 경과되었습니다."
|
||||
no_account = "계정이 없으신가요?"
|
||||
oidc_failed = "OIDC 로그인 처리에 실패했습니다. 다시 시도해 주세요."
|
||||
qr_expired = "시간이 경과되었습니다."
|
||||
qr_init_failed = "QR 초기화에 실패했습니다: {error}"
|
||||
qr_login_required = "로그인 한 상태여야 QR 스캔으로 로그인 할 수 있습니다"
|
||||
token_missing = "로그인 토큰을 확인할 수 없습니다."
|
||||
verification_failed = "승인 처리에 실패했습니다: {error}"
|
||||
|
||||
[msg.userfront.login.link]
|
||||
approved = "msg.userfront.login.link.approved"
|
||||
helper = "입력하신 정보로 로그인 링크를 전송합니다."
|
||||
missing_login_id = "이메일 또는 휴대폰 번호를 입력해 주세요."
|
||||
missing_phone = "휴대폰 번호를 입력해 주세요."
|
||||
resend_wait = "재발송은 {time} 후 가능합니다."
|
||||
short_code_help = "링크로 받은 값의 뒤 문자 2개와 숫자 6자리를 입력하셔도 로그인 할 수 있습니다."
|
||||
|
||||
[msg.userfront.login.password]
|
||||
failed = "로그인 실패: {error}"
|
||||
missing_credentials = "이메일(또는 전화번호)와 비밀번호를 모두 입력해주세요."
|
||||
|
||||
[msg.userfront.login.qr]
|
||||
load_failed = "QR 코드를 불러오지 못했습니다."
|
||||
scan_hint = "모바일 앱으로 스캔하세요"
|
||||
|
||||
[msg.userfront.login.short_code]
|
||||
invalid = "문자 2개와 숫자 6자리를 입력해 주세요."
|
||||
|
||||
[msg.userfront.login.unregistered]
|
||||
body = "가입되지 않은 정보입니다.\\\\n회원가입 후 이용해 주세요."
|
||||
|
||||
[msg.userfront.login.verification]
|
||||
approved = "승인되었습니다. 로그인은 요청하신 창에서 완료됩니다."
|
||||
approved_local = "승인 되었습니다. 이 기기는 로그인되어 있는 상태입니다. 원격 창도 로그인이 될 예정입니다"
|
||||
approved_remote = "요청하신 로그인이 완료되었습니다"
|
||||
pending_remote = "승인 요청을 확인하고 있습니다. 잠시만 기다려 주세요."
|
||||
close_hint = "이 창은 이제 닫으셔도 됩니다."
|
||||
success = "로그인 승인에 성공했습니다."
|
||||
|
||||
[msg.userfront.login_success]
|
||||
subtitle = "성공적으로 로그인되었습니다."
|
||||
|
||||
[msg.userfront.profile]
|
||||
department_missing = "소속 정보 없음"
|
||||
department_required = "소속을 입력해주세요."
|
||||
email_missing = "이메일 없음"
|
||||
greeting = "안녕하세요, {name}님"
|
||||
load_failed = "정보를 불러올 수 없습니다."
|
||||
name_missing = "이름 없음"
|
||||
name_required = "이름을 입력해주세요."
|
||||
phone_required = "휴대폰 번호를 입력해주세요."
|
||||
phone_verify_required = "휴대폰 번호 인증이 필요합니다."
|
||||
update_failed = "수정 실패: {error}"
|
||||
update_success = "정보가 수정되었습니다."
|
||||
|
||||
[msg.userfront.profile.password]
|
||||
change_failed = "비밀번호 변경 실패: {error}"
|
||||
changed = "비밀번호가 변경되었습니다."
|
||||
current_required = "현재 비밀번호를 입력해 주세요."
|
||||
mismatch = "새 비밀번호가 일치하지 않습니다."
|
||||
new_required = "새 비밀번호를 입력해 주세요."
|
||||
subtitle = "현재 비밀번호 확인 후 새 비밀번호로 변경합니다."
|
||||
|
||||
[msg.userfront.profile.phone]
|
||||
code_sent = "인증번호가 전송되었습니다."
|
||||
send_failed = "전송 실패: {error}"
|
||||
verified = "인증되었습니다."
|
||||
verify_failed = "인증 실패: {error}"
|
||||
verify_notice = "휴대폰 번호를 변경하려면 SMS 인증이 필요합니다."
|
||||
|
||||
[msg.userfront.profile.section]
|
||||
basic = "계정 기본 정보를 관리합니다."
|
||||
organization = "소속 및 구분 정보입니다."
|
||||
security = "비밀번호를 안전하게 관리합니다."
|
||||
|
||||
[msg.userfront.qr]
|
||||
approve_error = "msg.userfront.qr.approve_error"
|
||||
approve_success = "msg.userfront.qr.approve_success"
|
||||
camera_error = "카메라 오류: {error}"
|
||||
permission_error = "카메라 권한 요청에 실패했습니다. 브라우저/OS 설정을 확인해주세요."
|
||||
permission_required = "카메라 권한이 필요합니다."
|
||||
|
||||
[msg.userfront.reset]
|
||||
invalid_body = "비밀번호 재설정 링크가 만료되었거나 잘못되었습니다. 다시 시도해주세요."
|
||||
invalid_link = "유효하지 않은 재설정 링크입니다. (loginId/token 누락)"
|
||||
invalid_title = "유효하지 않은 링크입니다."
|
||||
policy_loading = "비밀번호 정책을 불러오는 중입니다..."
|
||||
success = "비밀번호가 성공적으로 변경되었습니다. 다시 로그인해주세요."
|
||||
|
||||
[msg.userfront.reset.error]
|
||||
empty_password = "비밀번호를 입력해주세요."
|
||||
generic = "비밀번호 변경에 실패했습니다: {error}"
|
||||
lowercase = "최소 1개 이상의 소문자를 포함해야 합니다."
|
||||
min_length = "비밀번호는 최소 {count}자 이상이어야 합니다."
|
||||
min_types = "비밀번호는 영문 대/소문자/숫자/특수문자 중 {count}가지 이상 포함해야 합니다."
|
||||
mismatch = "비밀번호가 일치하지 않습니다."
|
||||
number = "최소 1개 이상의 숫자를 포함해야 합니다."
|
||||
symbol = "최소 1개 이상의 특수문자를 포함해야 합니다."
|
||||
uppercase = "최소 1개 이상의 대문자를 포함해야 합니다."
|
||||
|
||||
[msg.userfront.reset.policy]
|
||||
lowercase = "소문자 1개 이상"
|
||||
min_length = "최소 {count}자 이상"
|
||||
min_types = "영문 대/소문자/숫자/특수문자 중 {count}가지 이상"
|
||||
number = "숫자 1개 이상"
|
||||
symbol = "특수문자 1개 이상"
|
||||
uppercase = "대문자 1개 이상"
|
||||
|
||||
[msg.userfront.sections]
|
||||
apps_subtitle = "현재 연결된 앱과 최근 인증 상태입니다."
|
||||
audit_subtitle = "Baron 로그인 기준의 최근 접근 기록입니다."
|
||||
|
||||
[msg.userfront.settings]
|
||||
disabled = "현재 계정 설정 화면은 준비 중입니다."
|
||||
|
||||
[msg.userfront.signup]
|
||||
failed = "가입 실패: {error}"
|
||||
privacy_full = "개인정보 수집 및 이용 동의 전문..."
|
||||
tos_full = "서비스 이용약관 전문..."
|
||||
|
||||
[msg.userfront.signup.agreement]
|
||||
all_hint = "필수 약관 2개를 모두 확인하고 동의하면 다음 단계로 진행할 수 있습니다."
|
||||
description = "계속 진행하려면 서비스 이용 조건과 개인정보 수집·이용 항목을 확인한 뒤 동의해주세요."
|
||||
privacy_summary = "개인정보 수집 항목, 이용 목적, 보관 기준을 안내합니다."
|
||||
progress = "필수 약관 {total}개 중 {count}개 동의 완료"
|
||||
title = "서비스 이용을 위해\\\\n약관에 동의해주세요"
|
||||
tos_summary = "서비스 이용 조건과 책임 범위를 확인할 수 있습니다."
|
||||
|
||||
[msg.userfront.signup.auth]
|
||||
affiliate_notice = "가족사 회원의 경우 반드시 회사 공식 이메일을 입력해주세요."
|
||||
title = "본인 확인을 위해\\\\n인증을 진행해주세요"
|
||||
|
||||
[msg.userfront.signup.email]
|
||||
code_mismatch = "인증코드가 일치하지 않습니다."
|
||||
duplicate = "이미 가입된 이메일입니다."
|
||||
invalid = "유효한 이메일 형식이 아닙니다."
|
||||
send_failed = "발송 실패: {error}"
|
||||
verified = "✅ 이메일 인증 완료"
|
||||
verify_failed = "인증 실패: {error}"
|
||||
|
||||
[msg.userfront.signup.password]
|
||||
length_required = "비밀번호는 최소 12자 이상이어야 합니다."
|
||||
lowercase_required = "소문자가 최소 1개 이상 포함되어야 합니다."
|
||||
mismatch = "비밀번호가 일치하지 않습니다."
|
||||
number_required = "숫자가 최소 1개 이상 포함되어야 합니다."
|
||||
symbol_required = "특수문자가 최소 1개 이상 포함되어야 합니다."
|
||||
title = "마지막으로\\\\n비밀번호를 설정해주세요"
|
||||
uppercase_required = "대문자가 최소 1개 이상 포함되어야 합니다."
|
||||
|
||||
[msg.userfront.signup.password.rule]
|
||||
lowercase = "소문자"
|
||||
min_length = "{count}자 이상"
|
||||
min_types = "문자 유형 {count}가지 이상"
|
||||
number = "숫자"
|
||||
symbol = "특수문자"
|
||||
uppercase = "대문자"
|
||||
|
||||
[msg.userfront.signup.phone]
|
||||
code_mismatch = "인증코드가 일치하지 않습니다."
|
||||
send_failed = "발송 실패: {error}"
|
||||
verified = "✅ 휴대폰 인증 완료"
|
||||
verify_failed = "인증 실패: {error}"
|
||||
|
||||
[msg.userfront.signup.policy]
|
||||
loading = "비밀번호 정책을 불러오는 중입니다..."
|
||||
lowercase = "소문자"
|
||||
min_length = "최소 {count}자 이상"
|
||||
min_types = "영문 대/소문자/숫자/특수문자 중 {count}가지 이상"
|
||||
number = "숫자"
|
||||
summary = "보안 정책: {rules}"
|
||||
symbol = "특수문자"
|
||||
uppercase = "대문자"
|
||||
|
||||
[msg.userfront.signup.profile]
|
||||
affiliate_hint = "가족사 이메일 사용 시 자동으로 선택됩니다."
|
||||
title = "회원님의\\\\n소속 정보를 알려주세요"
|
||||
|
||||
[msg.userfront.signup.success]
|
||||
body = "성공적으로 가입되었습니다."
|
||||
title = "회원가입 완료"
|
||||
|
||||
[ui.common]
|
||||
add = "추가"
|
||||
admin_only = "관리자 전용"
|
||||
all = "전체"
|
||||
assign = "할당"
|
||||
back = "돌아가기"
|
||||
back_to_login = "로그인으로 돌아가기"
|
||||
cancel = "취소"
|
||||
change_file = "파일 변경"
|
||||
clear_search = "검색 초기화"
|
||||
close = "닫기"
|
||||
collapse = "접기"
|
||||
confirm = "확인"
|
||||
copy = "복사"
|
||||
create = "생성"
|
||||
delete = "삭제"
|
||||
details = "상세정보"
|
||||
edit = "편집"
|
||||
enabled = "사용"
|
||||
export = "내보내기"
|
||||
fail = "실패"
|
||||
generate = "ui.common.generate"
|
||||
go_home = "홈으로"
|
||||
hyphen = "-"
|
||||
language = "언어"
|
||||
language_en = "English"
|
||||
language_ko = "한국어"
|
||||
manage = "관리"
|
||||
na = "N/A"
|
||||
never = "Never"
|
||||
next = "다음"
|
||||
none = "없음"
|
||||
page_of = "Page {page} of {total}"
|
||||
prev = "이전"
|
||||
previous = "이전"
|
||||
qr = "QR"
|
||||
read_only = "읽기 전용"
|
||||
refresh = "새로고침"
|
||||
remove = "제외"
|
||||
resend = "재발송"
|
||||
reset = "초기화"
|
||||
retry = "다시 시도"
|
||||
save = "저장"
|
||||
search = "검색"
|
||||
select = "선택"
|
||||
select_file = "파일 선택"
|
||||
select_placeholder = "선택하세요"
|
||||
show_more = "+ 더보기"
|
||||
success = "성공"
|
||||
theme_dark = "Dark"
|
||||
theme_light = "Light"
|
||||
theme_toggle = "테마 전환"
|
||||
unknown = "Unknown"
|
||||
view = "보기"
|
||||
|
||||
[ui.common.badge]
|
||||
admin_only = "Admin only"
|
||||
command_only = "Command only"
|
||||
system = "System"
|
||||
|
||||
[ui.common.status]
|
||||
active = "활성"
|
||||
archived = "보관됨"
|
||||
baron_guest = "Baron 게스트"
|
||||
blocked = "ui.common.status.blocked"
|
||||
extended_leave = "장기휴직"
|
||||
failure = "실패"
|
||||
inactive = "비활성"
|
||||
leave_of_absence = "휴직"
|
||||
ok = "정상"
|
||||
pending = "준비 중"
|
||||
preboarding = "입사대기"
|
||||
success = "성공"
|
||||
suspended = "정지"
|
||||
temporary_leave = "단기휴무"
|
||||
|
||||
[ui.userfront]
|
||||
app_title = "Baron SW 포탈"
|
||||
|
||||
[ui.userfront.app_label]
|
||||
admin_console = "Admin Console"
|
||||
baron = "Baron 로그인"
|
||||
dev_console = "Dev Console"
|
||||
|
||||
[ui.userfront.audit]
|
||||
|
||||
[ui.userfront.audit.table]
|
||||
action = "관리"
|
||||
app = "애플리케이션"
|
||||
auth_method = "인증수단"
|
||||
browser = "브라우저"
|
||||
date = "접속일자"
|
||||
device = "접속환경"
|
||||
ip = "IP"
|
||||
pending = "(준비중)"
|
||||
result = "인증결과"
|
||||
session_id = "Session ID"
|
||||
status = "현황"
|
||||
|
||||
[ui.userfront.auth_method]
|
||||
ory = "Ory 세션"
|
||||
session = "세션"
|
||||
|
||||
[ui.userfront.consent]
|
||||
accept = "동의하고 계속하기"
|
||||
requested_scopes = "요청된 권한"
|
||||
title = "접근 권한 요청"
|
||||
|
||||
[ui.userfront.consent.cancel]
|
||||
confirm_button = "예, 취소합니다"
|
||||
title = "동의 취소"
|
||||
|
||||
[ui.userfront.dashboard]
|
||||
last_auth_label = "최근 인증"
|
||||
status_history = "상태 이력"
|
||||
|
||||
[ui.userfront.dashboard.activity]
|
||||
linked = "연동됨"
|
||||
|
||||
[ui.userfront.dashboard.sessions]
|
||||
active_badge = "활성화"
|
||||
current_badge = "접속중"
|
||||
current_disabled = "현재 세션"
|
||||
unknown_device = "알 수 없는 기기"
|
||||
unknown_session = "세션 정보"
|
||||
|
||||
[ui.userfront.dashboard.sessions.revoke]
|
||||
action = "세션 종료"
|
||||
title = "세션 종료"
|
||||
|
||||
[ui.userfront.dashboard.approved_session]
|
||||
default = "승인한 세션 ID"
|
||||
userfront = "승인한 Userfront 세션 ID"
|
||||
|
||||
[ui.userfront.dashboard.revoke]
|
||||
confirm_button = "해지하기"
|
||||
title = "연동 해지"
|
||||
|
||||
[ui.userfront.dashboard.scopes]
|
||||
title = "동의 범위"
|
||||
|
||||
[ui.userfront.dashboard.status]
|
||||
revoked = "해지됨"
|
||||
|
||||
[ui.userfront.device]
|
||||
android = "Mobile(Android)"
|
||||
ios = "Mobile(iOS)"
|
||||
linux = "Desktop(Linux)"
|
||||
macos = "Desktop(macOS)"
|
||||
windows = "Desktop(Windows)"
|
||||
|
||||
[ui.userfront.error]
|
||||
go_home = "홈으로 이동"
|
||||
go_login = "로그인으로 이동"
|
||||
switch_account = "다른 계정으로 로그인"
|
||||
|
||||
[ui.userfront.forgot]
|
||||
heading = "비밀번호를 잊으셨나요?"
|
||||
input_label = "이메일 또는 휴대폰 번호"
|
||||
submit = "재설정 링크 전송"
|
||||
title = "비밀번호 재설정"
|
||||
|
||||
[ui.userfront.login]
|
||||
forgot_password = "비밀번호를 잊으셨나요?"
|
||||
signup = "회원가입"
|
||||
|
||||
[ui.userfront.login.action]
|
||||
submit = "로그인"
|
||||
|
||||
[ui.userfront.login.field]
|
||||
login_id = "이메일 또는 휴대폰 번호"
|
||||
password = "비밀번호"
|
||||
|
||||
[ui.userfront.login.link]
|
||||
action_label = "ui.userfront.login.link.action_label"
|
||||
code_only = "코드만 받기({time})"
|
||||
page_title = "ui.userfront.login.link.page_title"
|
||||
resend_with_time = "재발송 ({time})"
|
||||
send = "로그인 링크 전송"
|
||||
title = "ui.userfront.login.link.title"
|
||||
|
||||
[ui.userfront.login.qr]
|
||||
expired = "QR 코드 만료됨"
|
||||
refresh = "QR 코드 새로고침"
|
||||
remaining = "남은 시간: {time}"
|
||||
|
||||
[ui.userfront.login.short_code]
|
||||
digits = "숫자 6자리"
|
||||
expire_time = "유효시간 {time}"
|
||||
prefix = "영문 2자리"
|
||||
submit = "코드로 로그인"
|
||||
|
||||
[ui.userfront.login.tabs]
|
||||
link = "로그인 링크"
|
||||
password = "비밀번호"
|
||||
qr = "QR 코드"
|
||||
|
||||
[ui.userfront.login.unregistered]
|
||||
action = "회원가입 하기"
|
||||
title = "미등록 회원"
|
||||
|
||||
[ui.userfront.login.verification]
|
||||
action_label = "확인"
|
||||
action_label_remote = "로그인 창으로 이동하기"
|
||||
page_title = "Baron SW 포탈"
|
||||
title = "승인 완료"
|
||||
action_label_close = "창 닫기"
|
||||
title_pending = "로그인 승인 확인 중"
|
||||
title_remote = "로그인 승인 완료"
|
||||
|
||||
[ui.userfront.login_success]
|
||||
later = "나중에 하기 (대시보드로 이동)"
|
||||
qr = "QR 인증 (카메라 켜기)"
|
||||
title = "로그인 완료"
|
||||
|
||||
[ui.userfront.nav]
|
||||
dashboard = "대시보드"
|
||||
logout = "로그아웃"
|
||||
profile = "내 정보"
|
||||
qr_scan = "QR 스캔"
|
||||
|
||||
[ui.userfront.profile]
|
||||
department_empty = "소속 정보 없음"
|
||||
manage = "프로필 관리"
|
||||
user_fallback = "사용자"
|
||||
|
||||
[ui.userfront.profile.field]
|
||||
affiliation = "구분"
|
||||
company_code = "회사코드"
|
||||
department = "소속"
|
||||
email = "이메일"
|
||||
name = "이름"
|
||||
tenant = "소속 테넌트"
|
||||
tenant_slug = "테넌트 Slug"
|
||||
|
||||
[ui.userfront.profile.password]
|
||||
change = "비밀번호 변경"
|
||||
confirm = "새 비밀번호 확인"
|
||||
current = "현재 비밀번호"
|
||||
forgot = "비밀번호를 잊으셨나요?"
|
||||
new = "새 비밀번호"
|
||||
title = "비밀번호 변경"
|
||||
|
||||
[ui.userfront.profile.phone]
|
||||
code_hint = "인증번호 6자리"
|
||||
request_code = "인증요청"
|
||||
title = "전화번호"
|
||||
|
||||
[ui.userfront.profile.section]
|
||||
basic = "기본 정보"
|
||||
organization = "조직 정보"
|
||||
security = "보안"
|
||||
|
||||
[ui.userfront.qr]
|
||||
request_permission = "ui.userfront.qr.request_permission"
|
||||
rescan = "다시 스캔"
|
||||
result_failure = "ui.userfront.qr.result_failure"
|
||||
result_success = "승인 완료"
|
||||
title = "Scan QR Code"
|
||||
|
||||
[ui.userfront.reset]
|
||||
confirm_password = "새 비밀번호 확인"
|
||||
new_password = "새 비밀번호"
|
||||
submit = "비밀번호 변경"
|
||||
subtitle = "새로운 비밀번호 설정"
|
||||
title = "새 비밀번호 설정"
|
||||
|
||||
[ui.userfront.sections]
|
||||
apps = "나의 App 현황"
|
||||
audit = "접속이력"
|
||||
|
||||
[ui.userfront.session]
|
||||
active = "세션 활성"
|
||||
unknown = "알 수 없음"
|
||||
|
||||
[ui.userfront.signup]
|
||||
complete = "가입 완료"
|
||||
next_step = "다음 단계"
|
||||
title = "회원가입"
|
||||
|
||||
[ui.userfront.signup.agreement]
|
||||
all = "모두 동의합니다"
|
||||
privacy_title = "개인정보 수집 및 이용 동의 (필수)"
|
||||
required = "필수"
|
||||
tos_title = "바론 소프트웨어 이용약관 (필수)"
|
||||
|
||||
[ui.userfront.signup.auth]
|
||||
code_label = "인증코드 6자리"
|
||||
request_code = "인증요청"
|
||||
|
||||
[ui.userfront.signup.auth.email]
|
||||
label = "이메일 주소"
|
||||
title = "이메일 인증"
|
||||
|
||||
[ui.userfront.signup.password]
|
||||
confirm_label = "비밀번호 확인"
|
||||
label = "비밀번호"
|
||||
|
||||
[ui.userfront.signup.phone]
|
||||
label = "휴대폰 번호 (-없이)"
|
||||
title = "휴대폰 인증"
|
||||
|
||||
[ui.userfront.signup.profile]
|
||||
affiliation_type = "소속 유형"
|
||||
company = "가족사 선택"
|
||||
department = "부서명"
|
||||
department_optional = "소속 정보 (선택)"
|
||||
name = "이름"
|
||||
|
||||
[ui.userfront.signup.steps]
|
||||
agreement = "약관동의"
|
||||
password = "비밀번호"
|
||||
profile = "정보입력"
|
||||
verify = "본인인증"
|
||||
|
||||
[ui.userfront.signup.success]
|
||||
action = "로그인하기"
|
||||
|
||||
|
||||
[ui.userfront.audit.filter]
|
||||
title = "내 활동 관리"
|
||||
toggle_label = "활성 세션만 보기"
|
||||
|
||||
[msg.userfront.audit.filter]
|
||||
description = "활성화된 세션만 보려면 토글을 켜주세요."
|
||||
|
||||
902
baron-sso/userfront/assets/translations/template.toml
Normal file
@@ -0,0 +1,902 @@
|
||||
[domain]
|
||||
|
||||
[domain.affiliation]
|
||||
affiliate = ""
|
||||
general = ""
|
||||
|
||||
[domain.company]
|
||||
baron = ""
|
||||
halla = ""
|
||||
hanmac = ""
|
||||
jangheon = ""
|
||||
ptc = ""
|
||||
saman = ""
|
||||
|
||||
[domain.tenant_type]
|
||||
company = ""
|
||||
company_group = ""
|
||||
organization = ""
|
||||
personal = ""
|
||||
user_group = ""
|
||||
|
||||
[err.userfront]
|
||||
|
||||
[err.userfront.auth_proxy]
|
||||
consent_accept = ""
|
||||
consent_fetch = ""
|
||||
consent_reject = ""
|
||||
linked_app_revoke = ""
|
||||
login_failed = ""
|
||||
oidc_accept = ""
|
||||
password_reset_complete = ""
|
||||
password_reset_init = ""
|
||||
|
||||
[err.userfront.profile]
|
||||
load_failed = ""
|
||||
password_change_failed = ""
|
||||
send_code_failed = ""
|
||||
update_failed = ""
|
||||
verify_code_failed = ""
|
||||
|
||||
[err.userfront.session]
|
||||
missing = ""
|
||||
|
||||
[msg.userfront.error]
|
||||
detail_contact = ""
|
||||
detail_generic = ""
|
||||
detail_request = ""
|
||||
id = ""
|
||||
title = ""
|
||||
title_generic = ""
|
||||
title_with_code = ""
|
||||
type = ""
|
||||
|
||||
[msg.userfront.error.tenant]
|
||||
account = ""
|
||||
account_unknown = ""
|
||||
affiliated_tenants = ""
|
||||
allowed_box_title = ""
|
||||
allowed_tenants = ""
|
||||
detail = ""
|
||||
load_failed = ""
|
||||
loading = ""
|
||||
lookup_fallback = ""
|
||||
page_title = ""
|
||||
primary_tenant = ""
|
||||
tenant = ""
|
||||
tenant_unknown = ""
|
||||
title = ""
|
||||
|
||||
[msg.userfront.forgot]
|
||||
description = ""
|
||||
dry_send = ""
|
||||
error = ""
|
||||
input_required = ""
|
||||
sent = ""
|
||||
|
||||
[msg.userfront.login]
|
||||
cookie_check_failed = ""
|
||||
dry_send = ""
|
||||
link_failed = ""
|
||||
link_send_failed = ""
|
||||
link_sent_email = ""
|
||||
link_sent_phone = ""
|
||||
link_timeout = ""
|
||||
no_account = ""
|
||||
oidc_failed = ""
|
||||
qr_expired = ""
|
||||
qr_init_failed = ""
|
||||
qr_login_required = ""
|
||||
token_missing = ""
|
||||
verification_failed = ""
|
||||
|
||||
[msg.userfront.login_success]
|
||||
subtitle = ""
|
||||
|
||||
[msg.userfront.consent]
|
||||
accept_error = ""
|
||||
client_id = ""
|
||||
client_unknown = ""
|
||||
description = ""
|
||||
load_error = ""
|
||||
missing_redirect = ""
|
||||
redirect_notice = ""
|
||||
scope_count = ""
|
||||
|
||||
[msg.userfront.profile]
|
||||
department_missing = ""
|
||||
department_required = ""
|
||||
email_missing = ""
|
||||
greeting = ""
|
||||
load_failed = ""
|
||||
name_missing = ""
|
||||
name_required = ""
|
||||
phone_required = ""
|
||||
phone_verify_required = ""
|
||||
update_failed = ""
|
||||
update_success = ""
|
||||
|
||||
[msg.userfront.qr]
|
||||
camera_error = ""
|
||||
permission_error = ""
|
||||
permission_required = ""
|
||||
|
||||
[msg.userfront.reset]
|
||||
invalid_body = ""
|
||||
invalid_link = ""
|
||||
invalid_title = ""
|
||||
policy_loading = ""
|
||||
success = ""
|
||||
|
||||
[msg.userfront.sections]
|
||||
apps_subtitle = ""
|
||||
audit_subtitle = ""
|
||||
sessions_subtitle = ""
|
||||
|
||||
[msg.userfront.settings]
|
||||
disabled = ""
|
||||
|
||||
[msg.userfront.signup]
|
||||
failed = ""
|
||||
privacy_full = ""
|
||||
tos_full = ""
|
||||
|
||||
[ui.common.badge]
|
||||
admin_only = ""
|
||||
command_only = ""
|
||||
system = ""
|
||||
|
||||
[ui.common.status]
|
||||
active = ""
|
||||
blocked = ""
|
||||
failure = ""
|
||||
inactive = ""
|
||||
ok = ""
|
||||
pending = ""
|
||||
success = ""
|
||||
|
||||
[ui.userfront.app_label]
|
||||
admin_console = ""
|
||||
baron = ""
|
||||
dev_console = ""
|
||||
|
||||
[ui.userfront.auth_method]
|
||||
ory = ""
|
||||
session = ""
|
||||
|
||||
[ui.userfront.dashboard]
|
||||
link_status_label = ""
|
||||
last_auth_label = ""
|
||||
status_history = ""
|
||||
|
||||
[ui.userfront.device]
|
||||
android = ""
|
||||
ios = ""
|
||||
linux = ""
|
||||
macos = ""
|
||||
windows = ""
|
||||
|
||||
[ui.userfront.error]
|
||||
go_home = ""
|
||||
go_login = ""
|
||||
switch_account = ""
|
||||
|
||||
[ui.userfront.forgot]
|
||||
heading = ""
|
||||
input_label = ""
|
||||
submit = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.login]
|
||||
forgot_password = ""
|
||||
signup = ""
|
||||
|
||||
[ui.userfront.login_success]
|
||||
later = ""
|
||||
qr = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.consent]
|
||||
accept = ""
|
||||
requested_scopes = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.nav]
|
||||
dashboard = ""
|
||||
logout = ""
|
||||
profile = ""
|
||||
qr_scan = ""
|
||||
|
||||
[ui.userfront.profile]
|
||||
department_empty = ""
|
||||
manage = ""
|
||||
user_fallback = ""
|
||||
|
||||
[ui.userfront.qr]
|
||||
rescan = ""
|
||||
result_success = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.reset]
|
||||
confirm_password = ""
|
||||
new_password = ""
|
||||
submit = ""
|
||||
subtitle = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.sections]
|
||||
apps = ""
|
||||
audit = ""
|
||||
sessions = ""
|
||||
|
||||
[ui.userfront.session]
|
||||
active = ""
|
||||
unknown = ""
|
||||
|
||||
[ui.userfront.signup]
|
||||
complete = ""
|
||||
next_step = ""
|
||||
title = ""
|
||||
|
||||
[msg.userfront]
|
||||
greeting = ""
|
||||
|
||||
[msg.userfront.audit]
|
||||
browser = ""
|
||||
date = ""
|
||||
device = ""
|
||||
end = ""
|
||||
filtered_empty = ""
|
||||
ip = ""
|
||||
load_more_error = ""
|
||||
result = ""
|
||||
session_id = ""
|
||||
status = ""
|
||||
|
||||
[msg.userfront.consent]
|
||||
accept_error = ""
|
||||
client_id = ""
|
||||
client_unknown = ""
|
||||
description = ""
|
||||
load_error = ""
|
||||
missing_redirect = ""
|
||||
redirect_notice = ""
|
||||
scope_count = ""
|
||||
|
||||
[msg.userfront.consent.cancel]
|
||||
confirm = ""
|
||||
error = ""
|
||||
|
||||
[msg.userfront.consent.scope]
|
||||
email = ""
|
||||
offline_access = ""
|
||||
openid = ""
|
||||
phone = ""
|
||||
profile = ""
|
||||
|
||||
[msg.userfront.dashboard]
|
||||
approved_device = ""
|
||||
approved_ip = ""
|
||||
audit_empty = ""
|
||||
audit_load_error = ""
|
||||
auto_login_supported = ""
|
||||
auth_method = ""
|
||||
client_id = ""
|
||||
client_id_missing = ""
|
||||
current_status = ""
|
||||
last_auth = ""
|
||||
link_missing = ""
|
||||
link_open_error = ""
|
||||
render_error = ""
|
||||
session_id_copied = ""
|
||||
|
||||
[msg.userfront.dashboard.activities]
|
||||
empty = ""
|
||||
empty_detail = ""
|
||||
error = ""
|
||||
|
||||
[msg.userfront.dashboard.sessions]
|
||||
browser = ""
|
||||
empty = ""
|
||||
empty_detail = ""
|
||||
error = ""
|
||||
os = ""
|
||||
recent_app = ""
|
||||
session_id = ""
|
||||
|
||||
[msg.userfront.dashboard.sessions.revoke]
|
||||
confirm = ""
|
||||
error = ""
|
||||
success = ""
|
||||
|
||||
[msg.userfront.dashboard.approved_session]
|
||||
copy_click = ""
|
||||
copy_tap = ""
|
||||
none = ""
|
||||
|
||||
[msg.userfront.dashboard.revoke]
|
||||
confirm = ""
|
||||
error = ""
|
||||
success = ""
|
||||
|
||||
[msg.userfront.dashboard.scopes]
|
||||
empty = ""
|
||||
|
||||
[msg.userfront.dashboard.timeline]
|
||||
load_error = ""
|
||||
|
||||
[msg.userfront.error]
|
||||
detail_contact = ""
|
||||
detail_generic = ""
|
||||
detail_request = ""
|
||||
id = ""
|
||||
title = ""
|
||||
title_generic = ""
|
||||
title_with_code = ""
|
||||
type = ""
|
||||
|
||||
[msg.userfront.error.tenant]
|
||||
account = ""
|
||||
account_unknown = ""
|
||||
affiliated_tenants = ""
|
||||
allowed_box_title = ""
|
||||
allowed_tenants = ""
|
||||
detail = ""
|
||||
load_failed = ""
|
||||
loading = ""
|
||||
lookup_fallback = ""
|
||||
page_title = ""
|
||||
primary_tenant = ""
|
||||
tenant = ""
|
||||
tenant_unknown = ""
|
||||
title = ""
|
||||
|
||||
[msg.userfront.error.ory]
|
||||
"$normalizedCode" = ""
|
||||
access_denied = ""
|
||||
consent_required = ""
|
||||
interaction_required = ""
|
||||
invalid_client = ""
|
||||
invalid_grant = ""
|
||||
invalid_request = ""
|
||||
invalid_scope = ""
|
||||
login_required = ""
|
||||
request_forbidden = ""
|
||||
server_error = ""
|
||||
temporarily_unavailable = ""
|
||||
unauthorized_client = ""
|
||||
unsupported_response_type = ""
|
||||
|
||||
[msg.userfront.error.whitelist]
|
||||
"$normalizedCode" = ""
|
||||
bad_request = ""
|
||||
invalid_session = ""
|
||||
not_found = ""
|
||||
password_or_email_mismatch = ""
|
||||
rate_limited = ""
|
||||
recovery_expired = ""
|
||||
recovery_invalid = ""
|
||||
settings_disabled = ""
|
||||
verification_required = ""
|
||||
|
||||
[msg.userfront.forgot]
|
||||
description = ""
|
||||
dry_send = ""
|
||||
error = ""
|
||||
input_required = ""
|
||||
sent = ""
|
||||
|
||||
[msg.userfront.login]
|
||||
cookie_check_failed = ""
|
||||
dry_send = ""
|
||||
link_failed = ""
|
||||
link_send_failed = ""
|
||||
link_sent_email = ""
|
||||
link_sent_phone = ""
|
||||
link_timeout = ""
|
||||
no_account = ""
|
||||
oidc_failed = ""
|
||||
qr_expired = ""
|
||||
qr_init_failed = ""
|
||||
qr_login_required = ""
|
||||
token_missing = ""
|
||||
verification_failed = ""
|
||||
|
||||
[msg.userfront.login.link]
|
||||
approved = ""
|
||||
helper = ""
|
||||
missing_login_id = ""
|
||||
missing_phone = ""
|
||||
resend_wait = ""
|
||||
short_code_help = ""
|
||||
|
||||
[msg.userfront.login.password]
|
||||
failed = ""
|
||||
missing_credentials = ""
|
||||
|
||||
[msg.userfront.login.qr]
|
||||
load_failed = ""
|
||||
scan_hint = ""
|
||||
|
||||
[msg.userfront.login.short_code]
|
||||
invalid = ""
|
||||
|
||||
[msg.userfront.login.unregistered]
|
||||
body = ""
|
||||
|
||||
[msg.userfront.login.verification]
|
||||
approved = ""
|
||||
approved_local = ""
|
||||
approved_remote = ""
|
||||
pending_remote = ""
|
||||
close_hint = ""
|
||||
success = ""
|
||||
|
||||
[msg.userfront.login_success]
|
||||
subtitle = ""
|
||||
|
||||
[msg.userfront.profile]
|
||||
department_missing = ""
|
||||
department_required = ""
|
||||
email_missing = ""
|
||||
greeting = ""
|
||||
load_failed = ""
|
||||
name_missing = ""
|
||||
name_required = ""
|
||||
phone_required = ""
|
||||
phone_verify_required = ""
|
||||
update_failed = ""
|
||||
update_success = ""
|
||||
|
||||
[msg.userfront.profile.password]
|
||||
change_failed = ""
|
||||
changed = ""
|
||||
current_required = ""
|
||||
mismatch = ""
|
||||
new_required = ""
|
||||
subtitle = ""
|
||||
|
||||
[msg.userfront.profile.phone]
|
||||
code_sent = ""
|
||||
send_failed = ""
|
||||
verified = ""
|
||||
verify_failed = ""
|
||||
verify_notice = ""
|
||||
|
||||
[msg.userfront.profile.section]
|
||||
basic = ""
|
||||
organization = ""
|
||||
security = ""
|
||||
|
||||
[msg.userfront.qr]
|
||||
approve_error = ""
|
||||
approve_success = ""
|
||||
camera_error = ""
|
||||
permission_error = ""
|
||||
permission_required = ""
|
||||
|
||||
[msg.userfront.reset]
|
||||
invalid_body = ""
|
||||
invalid_link = ""
|
||||
invalid_title = ""
|
||||
policy_loading = ""
|
||||
success = ""
|
||||
|
||||
[msg.userfront.reset.error]
|
||||
empty_password = ""
|
||||
generic = ""
|
||||
lowercase = ""
|
||||
min_length = ""
|
||||
min_types = ""
|
||||
mismatch = ""
|
||||
number = ""
|
||||
symbol = ""
|
||||
uppercase = ""
|
||||
|
||||
[msg.userfront.reset.policy]
|
||||
lowercase = ""
|
||||
min_length = ""
|
||||
min_types = ""
|
||||
number = ""
|
||||
symbol = ""
|
||||
uppercase = ""
|
||||
|
||||
[msg.userfront.sections]
|
||||
apps_subtitle = ""
|
||||
audit_subtitle = ""
|
||||
|
||||
[msg.userfront.settings]
|
||||
disabled = ""
|
||||
|
||||
[msg.userfront.signup]
|
||||
failed = ""
|
||||
privacy_full = ""
|
||||
tos_full = ""
|
||||
|
||||
[msg.userfront.signup.agreement]
|
||||
all_hint = ""
|
||||
description = ""
|
||||
privacy_summary = ""
|
||||
progress = ""
|
||||
title = ""
|
||||
tos_summary = ""
|
||||
|
||||
[msg.userfront.signup.auth]
|
||||
affiliate_notice = ""
|
||||
title = ""
|
||||
|
||||
[msg.userfront.signup.email]
|
||||
code_mismatch = ""
|
||||
duplicate = ""
|
||||
invalid = ""
|
||||
send_failed = ""
|
||||
verified = ""
|
||||
verify_failed = ""
|
||||
|
||||
[msg.userfront.signup.password]
|
||||
length_required = ""
|
||||
lowercase_required = ""
|
||||
mismatch = ""
|
||||
number_required = ""
|
||||
symbol_required = ""
|
||||
title = ""
|
||||
uppercase_required = ""
|
||||
|
||||
[msg.userfront.signup.password.rule]
|
||||
lowercase = ""
|
||||
min_length = ""
|
||||
min_types = ""
|
||||
number = ""
|
||||
symbol = ""
|
||||
uppercase = ""
|
||||
|
||||
[msg.userfront.signup.phone]
|
||||
code_mismatch = ""
|
||||
send_failed = ""
|
||||
verified = ""
|
||||
verify_failed = ""
|
||||
|
||||
[msg.userfront.signup.policy]
|
||||
loading = ""
|
||||
lowercase = ""
|
||||
min_length = ""
|
||||
min_types = ""
|
||||
number = ""
|
||||
summary = ""
|
||||
symbol = ""
|
||||
uppercase = ""
|
||||
|
||||
[msg.userfront.signup.profile]
|
||||
affiliate_hint = ""
|
||||
title = ""
|
||||
|
||||
[msg.userfront.signup.success]
|
||||
body = ""
|
||||
title = ""
|
||||
|
||||
[ui.common]
|
||||
add = ""
|
||||
admin_only = ""
|
||||
all = ""
|
||||
assign = ""
|
||||
back = ""
|
||||
back_to_login = ""
|
||||
cancel = ""
|
||||
change_file = ""
|
||||
clear_search = ""
|
||||
close = ""
|
||||
collapse = ""
|
||||
confirm = ""
|
||||
copy = ""
|
||||
create = ""
|
||||
delete = ""
|
||||
details = ""
|
||||
edit = ""
|
||||
enabled = ""
|
||||
export = ""
|
||||
fail = ""
|
||||
generate = ""
|
||||
go_home = ""
|
||||
hyphen = ""
|
||||
language = ""
|
||||
language_en = ""
|
||||
language_ko = ""
|
||||
manage = ""
|
||||
na = ""
|
||||
never = ""
|
||||
next = ""
|
||||
none = ""
|
||||
page_of = ""
|
||||
prev = ""
|
||||
previous = ""
|
||||
qr = ""
|
||||
read_only = ""
|
||||
refresh = ""
|
||||
remove = ""
|
||||
resend = ""
|
||||
reset = ""
|
||||
retry = ""
|
||||
save = ""
|
||||
search = ""
|
||||
select = ""
|
||||
select_file = ""
|
||||
select_placeholder = ""
|
||||
show_more = ""
|
||||
success = ""
|
||||
theme_dark = ""
|
||||
theme_light = ""
|
||||
theme_toggle = ""
|
||||
unknown = ""
|
||||
view = ""
|
||||
|
||||
[ui.common.badge]
|
||||
admin_only = ""
|
||||
command_only = ""
|
||||
system = ""
|
||||
|
||||
[ui.common.status]
|
||||
active = ""
|
||||
archived = ""
|
||||
baron_guest = ""
|
||||
blocked = ""
|
||||
extended_leave = ""
|
||||
failure = ""
|
||||
inactive = ""
|
||||
leave_of_absence = ""
|
||||
ok = ""
|
||||
pending = ""
|
||||
preboarding = ""
|
||||
success = ""
|
||||
suspended = ""
|
||||
temporary_leave = ""
|
||||
|
||||
[ui.userfront]
|
||||
app_title = ""
|
||||
|
||||
[ui.userfront.app_label]
|
||||
admin_console = ""
|
||||
baron = ""
|
||||
dev_console = ""
|
||||
|
||||
[ui.userfront.audit]
|
||||
|
||||
[ui.userfront.audit.table]
|
||||
action = ""
|
||||
app = ""
|
||||
auth_method = ""
|
||||
browser = ""
|
||||
date = ""
|
||||
device = ""
|
||||
ip = ""
|
||||
pending = ""
|
||||
result = ""
|
||||
session_id = ""
|
||||
status = ""
|
||||
|
||||
[ui.userfront.auth_method]
|
||||
ory = ""
|
||||
session = ""
|
||||
|
||||
[ui.userfront.consent]
|
||||
accept = ""
|
||||
requested_scopes = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.consent.cancel]
|
||||
confirm_button = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.dashboard]
|
||||
last_auth_label = ""
|
||||
status_history = ""
|
||||
|
||||
[ui.userfront.dashboard.activity]
|
||||
linked = ""
|
||||
|
||||
[ui.userfront.dashboard.sessions]
|
||||
active_badge = ""
|
||||
current_badge = ""
|
||||
current_disabled = ""
|
||||
unknown_device = ""
|
||||
unknown_session = ""
|
||||
|
||||
[ui.userfront.dashboard.sessions.revoke]
|
||||
action = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.dashboard.approved_session]
|
||||
default = ""
|
||||
userfront = ""
|
||||
|
||||
[ui.userfront.dashboard.revoke]
|
||||
confirm_button = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.dashboard.scopes]
|
||||
title = ""
|
||||
|
||||
[ui.userfront.dashboard.status]
|
||||
revoked = ""
|
||||
|
||||
[ui.userfront.device]
|
||||
android = ""
|
||||
ios = ""
|
||||
linux = ""
|
||||
macos = ""
|
||||
windows = ""
|
||||
|
||||
[ui.userfront.error]
|
||||
go_home = ""
|
||||
go_login = ""
|
||||
switch_account = ""
|
||||
|
||||
[ui.userfront.forgot]
|
||||
heading = ""
|
||||
input_label = ""
|
||||
submit = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.login]
|
||||
forgot_password = ""
|
||||
signup = ""
|
||||
|
||||
[ui.userfront.login.action]
|
||||
submit = ""
|
||||
|
||||
[ui.userfront.login.field]
|
||||
login_id = ""
|
||||
password = ""
|
||||
|
||||
[ui.userfront.login.link]
|
||||
action_label = ""
|
||||
code_only = ""
|
||||
page_title = ""
|
||||
resend_with_time = ""
|
||||
send = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.login.qr]
|
||||
expired = ""
|
||||
refresh = ""
|
||||
remaining = ""
|
||||
|
||||
[ui.userfront.login.short_code]
|
||||
digits = ""
|
||||
expire_time = ""
|
||||
prefix = ""
|
||||
submit = ""
|
||||
|
||||
[ui.userfront.login.tabs]
|
||||
link = ""
|
||||
password = ""
|
||||
qr = ""
|
||||
|
||||
[ui.userfront.login.unregistered]
|
||||
action = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.login.verification]
|
||||
action_label = ""
|
||||
action_label_remote = ""
|
||||
action_label_close = ""
|
||||
page_title = ""
|
||||
title = ""
|
||||
title_pending = ""
|
||||
title_remote = ""
|
||||
|
||||
[ui.userfront.login_success]
|
||||
later = ""
|
||||
qr = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.nav]
|
||||
dashboard = ""
|
||||
logout = ""
|
||||
profile = ""
|
||||
qr_scan = ""
|
||||
|
||||
[ui.userfront.profile]
|
||||
department_empty = ""
|
||||
manage = ""
|
||||
user_fallback = ""
|
||||
|
||||
[ui.userfront.profile.field]
|
||||
affiliation = ""
|
||||
company_code = ""
|
||||
department = ""
|
||||
email = ""
|
||||
name = ""
|
||||
tenant = ""
|
||||
tenant_slug = ""
|
||||
|
||||
[ui.userfront.profile.password]
|
||||
change = ""
|
||||
confirm = ""
|
||||
current = ""
|
||||
forgot = ""
|
||||
new = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.profile.phone]
|
||||
code_hint = ""
|
||||
request_code = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.profile.section]
|
||||
basic = ""
|
||||
organization = ""
|
||||
security = ""
|
||||
|
||||
[ui.userfront.qr]
|
||||
request_permission = ""
|
||||
rescan = ""
|
||||
result_failure = ""
|
||||
result_success = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.reset]
|
||||
confirm_password = ""
|
||||
new_password = ""
|
||||
submit = ""
|
||||
subtitle = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.sections]
|
||||
apps = ""
|
||||
audit = ""
|
||||
|
||||
[ui.userfront.session]
|
||||
active = ""
|
||||
unknown = ""
|
||||
|
||||
[ui.userfront.signup]
|
||||
complete = ""
|
||||
next_step = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.signup.agreement]
|
||||
all = ""
|
||||
privacy_title = ""
|
||||
required = ""
|
||||
tos_title = ""
|
||||
|
||||
[ui.userfront.signup.auth]
|
||||
code_label = ""
|
||||
request_code = ""
|
||||
|
||||
[ui.userfront.signup.auth.email]
|
||||
label = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.signup.password]
|
||||
confirm_label = ""
|
||||
label = ""
|
||||
|
||||
[ui.userfront.signup.phone]
|
||||
label = ""
|
||||
title = ""
|
||||
|
||||
[ui.userfront.signup.profile]
|
||||
affiliation_type = ""
|
||||
company = ""
|
||||
department = ""
|
||||
department_optional = ""
|
||||
name = ""
|
||||
|
||||
[ui.userfront.signup.steps]
|
||||
agreement = ""
|
||||
password = ""
|
||||
profile = ""
|
||||
verify = ""
|
||||
|
||||
[ui.userfront.signup.success]
|
||||
action = ""
|
||||
|
||||
|
||||
[ui.userfront.audit.filter]
|
||||
title = ""
|
||||
toggle_label = ""
|
||||
|
||||
[msg.userfront.audit.filter]
|
||||
description = ""
|
||||
|
||||
34
baron-sso/userfront/ios/.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
**/dgph
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.moved-aside
|
||||
*.pbxuser
|
||||
*.perspectivev3
|
||||
**/*sync/
|
||||
.sconsign.dblite
|
||||
.tags*
|
||||
**/.vagrant/
|
||||
**/DerivedData/
|
||||
Icon?
|
||||
**/Pods/
|
||||
**/.symlinks/
|
||||
profile
|
||||
xcuserdata
|
||||
**/.generated/
|
||||
Flutter/App.framework
|
||||
Flutter/Flutter.framework
|
||||
Flutter/Flutter.podspec
|
||||
Flutter/Generated.xcconfig
|
||||
Flutter/ephemeral/
|
||||
Flutter/app.flx
|
||||
Flutter/app.zip
|
||||
Flutter/flutter_assets/
|
||||
Flutter/flutter_export_environment.sh
|
||||
ServiceDefinitions.json
|
||||
Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
# Exceptions to above rules.
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.pbxuser
|
||||
!default.perspectivev3
|
||||
26
baron-sso/userfront/ios/Flutter/AppFrameworkInfo.plist
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>App</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>io.flutter.flutter.app</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>App</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>13.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
1
baron-sso/userfront/ios/Flutter/Debug.xcconfig
Normal file
@@ -0,0 +1 @@
|
||||
#include "Generated.xcconfig"
|
||||
1
baron-sso/userfront/ios/Flutter/Release.xcconfig
Normal file
@@ -0,0 +1 @@
|
||||
#include "Generated.xcconfig"
|
||||
616
baron-sso/userfront/ios/Runner.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,616 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||
remoteInfo = Runner;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */,
|
||||
);
|
||||
path = RunnerTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||
);
|
||||
name = Flutter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146EF1CF9000F007C117D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
97C147021CF9000F007C117D /* Info.plist */,
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||
);
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
331C807D294A63A400263BE5 /* Sources */,
|
||||
331C807F294A63A400263BE5 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */,
|
||||
);
|
||||
name = RunnerTests;
|
||||
productName = RunnerTests;
|
||||
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Runner;
|
||||
productName = Runner;
|
||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1510;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
331C8080294A63A400263BE5 = {
|
||||
CreatedOnToolsVersion = 14.0;
|
||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||
};
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 97C146E51CF9000F007C117D;
|
||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
331C807F294A63A400263BE5 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Script";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
331C807D294A63A400263BE5 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C146FB1CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C147001CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
331C8088294A63A400263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
331C8089294A63A400263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
331C808A294A63A400263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
97C147031CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147041CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
97C147061CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147071CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = kr.co.baroncs.userfront;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
331C8088294A63A400263BE5 /* Debug */,
|
||||
331C8089294A63A400263BE5 /* Release */,
|
||||
331C808A294A63A400263BE5 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147031CF9000F007C117D /* Debug */,
|
||||
97C147041CF9000F007C117D /* Release */,
|
||||
249021D3217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147061CF9000F007C117D /* Debug */,
|
||||
97C147071CF9000F007C117D /* Release */,
|
||||
249021D4217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
}
|
||||
7
baron-sso/userfront/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1510"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
||||
BuildableName = "RunnerTests.xctest"
|
||||
BlueprintName = "RunnerTests"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
enableGPUValidationMode = "1"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Profile"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
7
baron-sso/userfront/ios/Runner.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
13
baron-sso/userfront/ios/Runner/AppDelegate.swift
Normal file
@@ -0,0 +1,13 @@
|
||||
import Flutter
|
||||
import UIKit
|
||||
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "Icon-App-1024x1024@1x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 236 KiB |
|
After Width: | Height: | Size: 954 B |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 21 KiB |
23
baron-sso/userfront/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
baron-sso/userfront/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
baron-sso/userfront/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
baron-sso/userfront/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
5
baron-sso/userfront/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Launch Screen Assets
|
||||
|
||||
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
|
||||
|
||||
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="LaunchImage" width="168" height="185"/>
|
||||
</resources>
|
||||
</document>
|
||||
26
baron-sso/userfront/ios/Runner/Base.lproj/Main.storyboard
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Flutter View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
51
baron-sso/userfront/ios/Runner/Info.plist
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Frontend</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>userfront</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>This app requires camera access to scan QR codes for login.</string>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
1
baron-sso/userfront/ios/Runner/Runner-Bridging-Header.h
Normal file
@@ -0,0 +1 @@
|
||||
#import "GeneratedPluginRegistrant.h"
|
||||
12
baron-sso/userfront/ios/RunnerTests/RunnerTests.swift
Normal file
@@ -0,0 +1,12 @@
|
||||
import Flutter
|
||||
import UIKit
|
||||
import XCTest
|
||||
|
||||
class RunnerTests: XCTestCase {
|
||||
|
||||
func testExample() {
|
||||
// If you add code to the Runner application, consider adding tests here.
|
||||
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||
}
|
||||
|
||||
}
|
||||
30
baron-sso/userfront/lib/core/constants/error_whitelist.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
const Map<String, String> internalErrorWhitelistMessageKeys = {
|
||||
'settings_disabled': 'msg.userfront.error.whitelist.settings_disabled',
|
||||
'invalid_session': 'msg.userfront.error.whitelist.invalid_session',
|
||||
'verification_required':
|
||||
'msg.userfront.error.whitelist.verification_required',
|
||||
'recovery_expired': 'msg.userfront.error.whitelist.recovery_expired',
|
||||
'recovery_invalid': 'msg.userfront.error.whitelist.recovery_invalid',
|
||||
'rate_limited': 'msg.userfront.error.whitelist.rate_limited',
|
||||
'not_found': 'msg.userfront.error.whitelist.not_found',
|
||||
'bad_request': 'msg.userfront.error.whitelist.bad_request',
|
||||
'password_or_email_mismatch':
|
||||
'msg.userfront.error.whitelist.password_or_email_mismatch',
|
||||
'tenant_not_allowed': 'msg.userfront.error.whitelist.tenant_not_allowed',
|
||||
};
|
||||
|
||||
const Set<String> oryBypassErrorCodes = {
|
||||
'access_denied',
|
||||
'consent_required',
|
||||
'interaction_required',
|
||||
'invalid_client',
|
||||
'invalid_grant',
|
||||
'invalid_request',
|
||||
'invalid_scope',
|
||||
'login_required',
|
||||
'request_forbidden',
|
||||
'server_error',
|
||||
'temporarily_unavailable',
|
||||
'unauthorized_client',
|
||||
'unsupported_response_type',
|
||||
};
|
||||
75
baron-sso/userfront/lib/core/i18n/locale_gate.dart
Normal file
@@ -0,0 +1,75 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart' hide tr;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:userfront/i18n.dart';
|
||||
import '../services/web_window.dart';
|
||||
import 'locale_storage.dart';
|
||||
import 'locale_utils.dart';
|
||||
|
||||
class LocaleGate extends StatefulWidget {
|
||||
const LocaleGate({super.key, required this.localeCode, required this.child});
|
||||
|
||||
final String localeCode;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
State<LocaleGate> createState() => _LocaleGateState();
|
||||
}
|
||||
|
||||
class _LocaleGateState extends State<LocaleGate> {
|
||||
bool _syncScheduled = false;
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_scheduleLocaleSync();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(LocaleGate oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.localeCode != widget.localeCode) {
|
||||
_scheduleLocaleSync();
|
||||
}
|
||||
}
|
||||
|
||||
void _scheduleLocaleSync() {
|
||||
if (_syncScheduled) {
|
||||
return;
|
||||
}
|
||||
_syncScheduled = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_syncScheduled = false;
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
unawaited(_applyLocale());
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _applyLocale() async {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
final normalized = normalizeLocaleCode(widget.localeCode);
|
||||
LocaleStorage.write(normalized);
|
||||
final localization = EasyLocalization.of(context);
|
||||
if (localization == null) {
|
||||
return;
|
||||
}
|
||||
if (localization.currentLocale?.languageCode == normalized) {
|
||||
webWindow.setTitle(tr('ui.userfront.app_title'));
|
||||
return;
|
||||
}
|
||||
await localization.setLocale(Locale(normalized));
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
webWindow.setTitle(tr('ui.userfront.app_title'));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => widget.child;
|
||||
}
|
||||
115
baron-sso/userfront/lib/core/i18n/locale_registry.dart
Normal file
@@ -0,0 +1,115 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
const _translationAssetPrefix = 'assets/translations/';
|
||||
const _templateFileName = 'template.toml';
|
||||
const _safeFallbackLocaleCode = 'en';
|
||||
|
||||
List<String> extractSupportedLocaleCodesFromAssets(Iterable<String> assets) {
|
||||
final localeCodes = <String>{};
|
||||
for (final asset in assets) {
|
||||
if (!asset.startsWith(_translationAssetPrefix) ||
|
||||
!asset.endsWith('.toml')) {
|
||||
continue;
|
||||
}
|
||||
final fileName = asset.substring(_translationAssetPrefix.length);
|
||||
if (fileName.contains('/') || fileName == _templateFileName) {
|
||||
continue;
|
||||
}
|
||||
final rawCode = fileName.substring(0, fileName.length - '.toml'.length);
|
||||
final normalized = rawCode.toLowerCase().replaceAll('_', '-');
|
||||
if (_isValidLocaleCode(normalized)) {
|
||||
localeCodes.add(normalized);
|
||||
}
|
||||
}
|
||||
|
||||
final sorted = localeCodes.toList()..sort();
|
||||
return sorted;
|
||||
}
|
||||
|
||||
class LocaleRegistry {
|
||||
static final Set<String> _localeCodes = <String>{};
|
||||
static bool _initialized = false;
|
||||
|
||||
static void primeWithDefaults({
|
||||
Iterable<String> localeCodes = const ['en', 'ko'],
|
||||
}) {
|
||||
if (_localeCodes.isNotEmpty) {
|
||||
return;
|
||||
}
|
||||
_localeCodes.addAll(
|
||||
localeCodes
|
||||
.map((code) => code.toLowerCase().replaceAll('_', '-'))
|
||||
.where(_isValidLocaleCode),
|
||||
);
|
||||
if (_localeCodes.isEmpty) {
|
||||
_localeCodes.add(_safeFallbackLocaleCode);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> initialize({AssetBundle? assetBundle}) async {
|
||||
if (_initialized) {
|
||||
return;
|
||||
}
|
||||
final bundle = assetBundle ?? rootBundle;
|
||||
try {
|
||||
final manifest = await AssetManifest.loadFromAssetBundle(bundle);
|
||||
final extracted = extractSupportedLocaleCodesFromAssets(
|
||||
manifest.listAssets(),
|
||||
);
|
||||
_localeCodes.addAll(extracted);
|
||||
} catch (_) {
|
||||
// manifest 로딩 실패 시 안전 fallback으로 계속 진행합니다.
|
||||
}
|
||||
|
||||
if (_localeCodes.isEmpty) {
|
||||
_localeCodes.add(_safeFallbackLocaleCode);
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
static List<String> get supportedLocaleCodes {
|
||||
final sorted = _localeCodes.toList()..sort();
|
||||
return List.unmodifiable(sorted);
|
||||
}
|
||||
|
||||
static String get fallbackLocaleCode {
|
||||
final supported = supportedLocaleCodes;
|
||||
if (supported.isEmpty) {
|
||||
return _safeFallbackLocaleCode;
|
||||
}
|
||||
if (supported.contains('en')) {
|
||||
return 'en';
|
||||
}
|
||||
return supported.first;
|
||||
}
|
||||
|
||||
static bool contains(String code) {
|
||||
return _localeCodes.contains(code.toLowerCase());
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
static void setSupportedLocaleCodesForTest(Iterable<String> localeCodes) {
|
||||
_localeCodes
|
||||
..clear()
|
||||
..addAll(
|
||||
localeCodes
|
||||
.map((code) => code.toLowerCase().replaceAll('_', '-'))
|
||||
.where(_isValidLocaleCode),
|
||||
);
|
||||
if (_localeCodes.isEmpty) {
|
||||
_localeCodes.add(_safeFallbackLocaleCode);
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
static void resetForTest() {
|
||||
_localeCodes.clear();
|
||||
_initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool _isValidLocaleCode(String value) {
|
||||
return RegExp(r'^[a-z]{2,3}$').hasMatch(value);
|
||||
}
|
||||
59
baron-sso/userfront/lib/core/i18n/locale_storage.dart
Normal file
@@ -0,0 +1,59 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'locale_storage_backend.dart';
|
||||
import 'locale_storage_stub.dart'
|
||||
if (dart.library.js_interop) 'locale_storage_web.dart';
|
||||
|
||||
abstract class LocaleStorage {
|
||||
static bool _forceMemory = false;
|
||||
static bool _forceSession = false;
|
||||
|
||||
static void _syncTestMode() {
|
||||
if (_forceMemory) {
|
||||
localeStorage.setTestMode(LocaleStorageTestMode.memoryOnly);
|
||||
return;
|
||||
}
|
||||
if (_forceSession) {
|
||||
localeStorage.setTestMode(LocaleStorageTestMode.sessionOnly);
|
||||
return;
|
||||
}
|
||||
localeStorage.setTestMode(LocaleStorageTestMode.normal);
|
||||
}
|
||||
|
||||
static String? read() => localeStorage.read();
|
||||
static void write(String locale) => localeStorage.write(locale);
|
||||
|
||||
@visibleForTesting
|
||||
static void setTestModeForTests(LocaleStorageTestMode mode) {
|
||||
_forceMemory = mode == LocaleStorageTestMode.memoryOnly;
|
||||
_forceSession = mode == LocaleStorageTestMode.sessionOnly;
|
||||
_syncTestMode();
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
static void clearForTests() {
|
||||
localeStorage.clearForTests();
|
||||
_forceMemory = false;
|
||||
_forceSession = false;
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
static void seedLegacyForTests(String locale) {
|
||||
localeStorage.seedLegacyForTests(locale);
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
static LocaleStorageDebugState debugStateForTests() {
|
||||
return localeStorage.debugStateForTests();
|
||||
}
|
||||
|
||||
static void forceMemoryStorageForTests(bool value) {
|
||||
_forceMemory = value;
|
||||
_syncTestMode();
|
||||
}
|
||||
|
||||
static void forceSessionStorageForTests(bool value) {
|
||||
_forceSession = value;
|
||||
_syncTestMode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
enum LocaleStorageTestMode { normal, sessionOnly, memoryOnly }
|
||||
|
||||
@immutable
|
||||
class LocaleStorageDebugState {
|
||||
const LocaleStorageDebugState({
|
||||
required this.mode,
|
||||
this.localCurrent,
|
||||
this.localLegacy,
|
||||
this.sessionCurrent,
|
||||
this.sessionLegacy,
|
||||
this.memoryCurrent,
|
||||
this.memoryLegacy,
|
||||
});
|
||||
|
||||
final LocaleStorageTestMode mode;
|
||||
final String? localCurrent;
|
||||
final String? localLegacy;
|
||||
final String? sessionCurrent;
|
||||
final String? sessionLegacy;
|
||||
final String? memoryCurrent;
|
||||
final String? memoryLegacy;
|
||||
}
|
||||
|
||||
abstract interface class LocaleStorageBackend {
|
||||
String? read();
|
||||
|
||||
void write(String locale);
|
||||
|
||||
void setTestMode(LocaleStorageTestMode mode);
|
||||
|
||||
void clearForTests();
|
||||
|
||||
void seedLegacyForTests(String locale);
|
||||
|
||||
LocaleStorageDebugState debugStateForTests();
|
||||
}
|
||||
245
baron-sso/userfront/lib/core/i18n/locale_storage_engine.dart
Normal file
@@ -0,0 +1,245 @@
|
||||
import 'locale_storage_backend.dart';
|
||||
import 'locale_storage_policy.dart';
|
||||
|
||||
enum _StorageTarget { local, session, memory }
|
||||
|
||||
abstract interface class LocaleStorageTarget {
|
||||
String? read(String key);
|
||||
|
||||
bool write(String key, String value);
|
||||
|
||||
bool remove(String key);
|
||||
|
||||
void clear();
|
||||
}
|
||||
|
||||
class LocaleStorageNoopTarget implements LocaleStorageTarget {
|
||||
const LocaleStorageNoopTarget();
|
||||
|
||||
@override
|
||||
String? read(String key) => null;
|
||||
|
||||
@override
|
||||
bool write(String key, String value) => false;
|
||||
|
||||
@override
|
||||
bool remove(String key) => false;
|
||||
|
||||
@override
|
||||
void clear() {}
|
||||
}
|
||||
|
||||
class LocaleStorageCallbackTarget implements LocaleStorageTarget {
|
||||
LocaleStorageCallbackTarget({
|
||||
required this.readCallback,
|
||||
required this.writeCallback,
|
||||
required this.removeCallback,
|
||||
required this.clearCallback,
|
||||
});
|
||||
|
||||
final String? Function(String key) readCallback;
|
||||
final void Function(String key, String value) writeCallback;
|
||||
final void Function(String key) removeCallback;
|
||||
final void Function() clearCallback;
|
||||
|
||||
@override
|
||||
String? read(String key) => readCallback(key);
|
||||
|
||||
@override
|
||||
bool write(String key, String value) {
|
||||
writeCallback(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
bool remove(String key) {
|
||||
removeCallback(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
void clear() => clearCallback();
|
||||
}
|
||||
|
||||
class LocaleStorageEngine implements LocaleStorageBackend {
|
||||
LocaleStorageEngine({
|
||||
required LocaleStorageTarget localTarget,
|
||||
required LocaleStorageTarget sessionTarget,
|
||||
}) : _localTarget = localTarget,
|
||||
_sessionTarget = sessionTarget;
|
||||
|
||||
final LocaleStorageTarget _localTarget;
|
||||
final LocaleStorageTarget _sessionTarget;
|
||||
final Map<String, String> _memory = {};
|
||||
LocaleStorageTestMode _mode = LocaleStorageTestMode.normal;
|
||||
|
||||
List<_StorageTarget> _fallbackTargets() {
|
||||
switch (_mode) {
|
||||
case LocaleStorageTestMode.normal:
|
||||
return [
|
||||
_StorageTarget.local,
|
||||
_StorageTarget.session,
|
||||
_StorageTarget.memory,
|
||||
];
|
||||
case LocaleStorageTestMode.sessionOnly:
|
||||
return [_StorageTarget.session, _StorageTarget.memory];
|
||||
case LocaleStorageTestMode.memoryOnly:
|
||||
return [_StorageTarget.memory];
|
||||
}
|
||||
}
|
||||
|
||||
String? _safeReadTarget(_StorageTarget target, String key) {
|
||||
try {
|
||||
switch (target) {
|
||||
case _StorageTarget.local:
|
||||
return _localTarget.read(key);
|
||||
case _StorageTarget.session:
|
||||
return _sessionTarget.read(key);
|
||||
case _StorageTarget.memory:
|
||||
return _memory[key];
|
||||
}
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
bool _safeWriteTarget(_StorageTarget target, String key, String value) {
|
||||
try {
|
||||
switch (target) {
|
||||
case _StorageTarget.local:
|
||||
return _localTarget.write(key, value);
|
||||
case _StorageTarget.session:
|
||||
return _sessionTarget.write(key, value);
|
||||
case _StorageTarget.memory:
|
||||
_memory[key] = value;
|
||||
return true;
|
||||
}
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool _safeRemoveTarget(_StorageTarget target, String key) {
|
||||
try {
|
||||
switch (target) {
|
||||
case _StorageTarget.local:
|
||||
return _localTarget.remove(key);
|
||||
case _StorageTarget.session:
|
||||
return _sessionTarget.remove(key);
|
||||
case _StorageTarget.memory:
|
||||
_memory.remove(key);
|
||||
return true;
|
||||
}
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void _safeClearTarget(_StorageTarget target) {
|
||||
try {
|
||||
switch (target) {
|
||||
case _StorageTarget.local:
|
||||
_localTarget.clear();
|
||||
case _StorageTarget.session:
|
||||
_sessionTarget.clear();
|
||||
case _StorageTarget.memory:
|
||||
_memory.clear();
|
||||
}
|
||||
} catch (_) {
|
||||
// 테스트 정리 단계에서는 clear 예외를 무시합니다.
|
||||
}
|
||||
}
|
||||
|
||||
String? _readByKey(String key) {
|
||||
for (final target in _fallbackTargets()) {
|
||||
final value = _safeReadTarget(target, key);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void _writeByKey(String key, String value) {
|
||||
for (final target in _fallbackTargets()) {
|
||||
if (_safeWriteTarget(target, key, value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _removeEverywhere(String key) {
|
||||
_safeRemoveTarget(_StorageTarget.local, key);
|
||||
_safeRemoveTarget(_StorageTarget.session, key);
|
||||
_memory.remove(key);
|
||||
}
|
||||
|
||||
@override
|
||||
String? read() {
|
||||
final current = _readByKey(LocaleStoragePolicy.currentKey);
|
||||
if (LocaleStoragePolicy.hasValue(current)) {
|
||||
return current;
|
||||
}
|
||||
|
||||
final legacy = _readByKey(LocaleStoragePolicy.legacyKey);
|
||||
if (LocaleStoragePolicy.shouldMigrateLegacy(
|
||||
current: current,
|
||||
legacy: legacy,
|
||||
) &&
|
||||
legacy != null) {
|
||||
_writeByKey(LocaleStoragePolicy.currentKey, legacy);
|
||||
_removeEverywhere(LocaleStoragePolicy.legacyKey);
|
||||
return legacy;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
void write(String locale) {
|
||||
_writeByKey(LocaleStoragePolicy.currentKey, locale);
|
||||
}
|
||||
|
||||
@override
|
||||
void setTestMode(LocaleStorageTestMode mode) {
|
||||
_mode = mode;
|
||||
}
|
||||
|
||||
@override
|
||||
void clearForTests() {
|
||||
_safeClearTarget(_StorageTarget.local);
|
||||
_safeClearTarget(_StorageTarget.session);
|
||||
_memory.clear();
|
||||
_mode = LocaleStorageTestMode.normal;
|
||||
}
|
||||
|
||||
@override
|
||||
void seedLegacyForTests(String locale) {
|
||||
_writeByKey(LocaleStoragePolicy.legacyKey, locale);
|
||||
}
|
||||
|
||||
@override
|
||||
LocaleStorageDebugState debugStateForTests() {
|
||||
return LocaleStorageDebugState(
|
||||
mode: _mode,
|
||||
localCurrent: _safeReadTarget(
|
||||
_StorageTarget.local,
|
||||
LocaleStoragePolicy.currentKey,
|
||||
),
|
||||
localLegacy: _safeReadTarget(
|
||||
_StorageTarget.local,
|
||||
LocaleStoragePolicy.legacyKey,
|
||||
),
|
||||
sessionCurrent: _safeReadTarget(
|
||||
_StorageTarget.session,
|
||||
LocaleStoragePolicy.currentKey,
|
||||
),
|
||||
sessionLegacy: _safeReadTarget(
|
||||
_StorageTarget.session,
|
||||
LocaleStoragePolicy.legacyKey,
|
||||
),
|
||||
memoryCurrent: _memory[LocaleStoragePolicy.currentKey],
|
||||
memoryLegacy: _memory[LocaleStoragePolicy.legacyKey],
|
||||
);
|
||||
}
|
||||
}
|
||||
13
baron-sso/userfront/lib/core/i18n/locale_storage_policy.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
class LocaleStoragePolicy {
|
||||
static const currentKey = 'locale';
|
||||
static const legacyKey = 'baron_locale';
|
||||
|
||||
static bool hasValue(String? value) => value != null && value.isNotEmpty;
|
||||
|
||||
static bool shouldMigrateLegacy({
|
||||
required String? current,
|
||||
required String? legacy,
|
||||
}) {
|
||||
return !hasValue(current) && hasValue(legacy);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import 'locale_storage_backend.dart';
|
||||
import 'locale_storage_engine.dart';
|
||||
|
||||
final LocaleStorageBackend localeStorage = LocaleStorageEngine(
|
||||
localTarget: const LocaleStorageNoopTarget(),
|
||||
sessionTarget: const LocaleStorageNoopTarget(),
|
||||
);
|
||||
22
baron-sso/userfront/lib/core/i18n/locale_storage_web.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
// ignore_for_file: avoid_web_libraries_in_flutter
|
||||
|
||||
import 'package:web/web.dart' as web;
|
||||
|
||||
import 'locale_storage_backend.dart';
|
||||
import 'locale_storage_engine.dart';
|
||||
|
||||
final LocaleStorageBackend localeStorage = LocaleStorageEngine(
|
||||
localTarget: LocaleStorageCallbackTarget(
|
||||
readCallback: (key) => web.window.localStorage.getItem(key),
|
||||
writeCallback: (key, value) => web.window.localStorage.setItem(key, value),
|
||||
removeCallback: (key) => web.window.localStorage.removeItem(key),
|
||||
clearCallback: () => web.window.localStorage.clear(),
|
||||
),
|
||||
sessionTarget: LocaleStorageCallbackTarget(
|
||||
readCallback: (key) => web.window.sessionStorage.getItem(key),
|
||||
writeCallback: (key, value) =>
|
||||
web.window.sessionStorage.setItem(key, value),
|
||||
removeCallback: (key) => web.window.sessionStorage.removeItem(key),
|
||||
clearCallback: () => web.window.sessionStorage.clear(),
|
||||
),
|
||||
);
|
||||
117
baron-sso/userfront/lib/core/i18n/locale_utils.dart
Normal file
@@ -0,0 +1,117 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'locale_storage.dart';
|
||||
import 'locale_registry.dart';
|
||||
|
||||
String get defaultLocaleCode => LocaleRegistry.fallbackLocaleCode;
|
||||
|
||||
String normalizeLocaleCode(String? code) {
|
||||
final supportedLocaleCodes = LocaleRegistry.supportedLocaleCodes;
|
||||
final fallbackLocaleCode = LocaleRegistry.fallbackLocaleCode;
|
||||
|
||||
if (code == null || code.isEmpty) {
|
||||
return fallbackLocaleCode;
|
||||
}
|
||||
final normalized = code.toLowerCase().replaceAll('_', '-');
|
||||
if (supportedLocaleCodes.contains(normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
final languageCode = normalized.split('-').first;
|
||||
if (supportedLocaleCodes.contains(languageCode)) {
|
||||
return languageCode;
|
||||
}
|
||||
return fallbackLocaleCode;
|
||||
}
|
||||
|
||||
String resolvePreferredLocaleCode() {
|
||||
final stored = LocaleStorage.read();
|
||||
if (stored != null && stored.isNotEmpty) {
|
||||
final normalizedStored = normalizeLocaleCode(stored);
|
||||
if (LocaleRegistry.contains(normalizedStored)) {
|
||||
return normalizedStored;
|
||||
}
|
||||
}
|
||||
final deviceLocale = PlatformDispatcher.instance.locale;
|
||||
final countryCode = deviceLocale.countryCode;
|
||||
final languageTag = countryCode == null || countryCode.isEmpty
|
||||
? deviceLocale.languageCode
|
||||
: '${deviceLocale.languageCode}-$countryCode';
|
||||
return normalizeLocaleCode(languageTag);
|
||||
}
|
||||
|
||||
String? extractLocaleFromPath(Uri uri) {
|
||||
final supportedLocaleCodes = LocaleRegistry.supportedLocaleCodes;
|
||||
if (uri.pathSegments.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final code = uri.pathSegments.first.toLowerCase();
|
||||
if (supportedLocaleCodes.contains(code)) {
|
||||
return code;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String stripLocalePath(Uri uri) {
|
||||
final supportedLocaleCodes = LocaleRegistry.supportedLocaleCodes;
|
||||
final segments = uri.pathSegments;
|
||||
if (segments.isNotEmpty &&
|
||||
supportedLocaleCodes.contains(segments.first.toLowerCase())) {
|
||||
final rest = segments.skip(1).join('/');
|
||||
if (rest.isEmpty) {
|
||||
return '/';
|
||||
}
|
||||
return '/$rest';
|
||||
}
|
||||
return uri.path;
|
||||
}
|
||||
|
||||
String buildLocalizedPath(String localeCode, Uri uri) {
|
||||
final supportedLocaleCodes = LocaleRegistry.supportedLocaleCodes;
|
||||
final segments = uri.pathSegments;
|
||||
Iterable<String> restSegments = segments;
|
||||
if (segments.isNotEmpty) {
|
||||
final head = segments.first.toLowerCase();
|
||||
if (supportedLocaleCodes.contains(head)) {
|
||||
restSegments = segments.skip(1);
|
||||
}
|
||||
}
|
||||
final newPath = '/${[localeCode, ...restSegments].join('/')}';
|
||||
|
||||
// Return only the path and query part to avoid GoRouter confusion with full URLs
|
||||
final newUri = uri.replace(path: newPath);
|
||||
String result = newUri.path;
|
||||
if (newUri.hasQuery) {
|
||||
result += '?${newUri.query}';
|
||||
}
|
||||
if (newUri.hasFragment) {
|
||||
result += '#${newUri.fragment}';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String buildSigninRedirectPath(String localeCode, Uri uri) {
|
||||
final newPath = '/$localeCode/signin';
|
||||
final newUri = uri.replace(path: newPath);
|
||||
String result = newUri.path;
|
||||
if (newUri.hasQuery) {
|
||||
result += '?${newUri.query}';
|
||||
}
|
||||
if (newUri.hasFragment) {
|
||||
result += '#${newUri.fragment}';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String buildLocalizedHomePath(Uri uri, {String? preferredLocaleCode}) {
|
||||
final resolvedLocale =
|
||||
extractLocaleFromPath(uri) ??
|
||||
normalizeLocaleCode(preferredLocaleCode ?? resolvePreferredLocaleCode());
|
||||
return '/$resolvedLocale/dashboard';
|
||||
}
|
||||
|
||||
String buildLocalizedSigninPath(Uri uri, {String? preferredLocaleCode}) {
|
||||
final resolvedLocale =
|
||||
extractLocaleFromPath(uri) ??
|
||||
normalizeLocaleCode(preferredLocaleCode ?? resolvePreferredLocaleCode());
|
||||
return '/$resolvedLocale/signin';
|
||||
}
|
||||
54
baron-sso/userfront/lib/core/i18n/toml_asset_loader.dart
Normal file
@@ -0,0 +1,54 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
import '../../i18n_data.dart';
|
||||
|
||||
class TomlAssetLoader extends AssetLoader {
|
||||
const TomlAssetLoader();
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> load(String path, Locale locale) async {
|
||||
final languageCode = locale.languageCode.toLowerCase();
|
||||
return switch (languageCode) {
|
||||
'ko' => _normalizedKoStrings,
|
||||
'en' => _normalizedEnStrings,
|
||||
_ => _normalizedEnStrings,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
final Map<String, dynamic> _normalizedKoStrings = _normalizeFlatTranslations(
|
||||
koStrings,
|
||||
);
|
||||
final Map<String, dynamic> _normalizedEnStrings = _normalizeFlatTranslations(
|
||||
enStrings,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _normalizeFlatTranslations(Map<String, String> flatMap) =>
|
||||
Map.fromEntries(
|
||||
flatMap.entries
|
||||
.where((entry) => _isUserfrontTranslationKey(entry.key))
|
||||
.map(
|
||||
(entry) =>
|
||||
MapEntry(entry.key, _normalizeLocalizationValue(entry.value)),
|
||||
),
|
||||
);
|
||||
|
||||
bool _isUserfrontTranslationKey(String key) {
|
||||
return key.startsWith('domain.') ||
|
||||
key.startsWith('err.userfront.') ||
|
||||
key.startsWith('msg.userfront.') ||
|
||||
key.startsWith('ui.userfront.') ||
|
||||
key.startsWith('ui.common.');
|
||||
}
|
||||
|
||||
String _normalizeLocalizationValue(String value) {
|
||||
return value
|
||||
.replaceAllMapped(
|
||||
RegExp(r'\{\{\s*([a-zA-Z0-9_]+)\s*\}\}'),
|
||||
(match) => '{${match.group(1)}}',
|
||||
)
|
||||
.replaceAll(r'\\n', '\n')
|
||||
.replaceAll(r'\n', '\n');
|
||||
}
|
||||
16
baron-sso/userfront/lib/core/notifiers/auth_notifier.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../services/auth_token_store.dart';
|
||||
|
||||
class AuthNotifier extends ChangeNotifier {
|
||||
static final AuthNotifier instance = AuthNotifier();
|
||||
|
||||
Future<void> onLoginSuccess(String token, {String? provider}) async {
|
||||
AuthTokenStore.setToken(token, provider: provider);
|
||||
AuthTokenStore.clearPendingProvider();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void notify() {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
40
baron-sso/userfront/lib/core/services/audit_service.dart
Normal file
@@ -0,0 +1,40 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'runtime_env.dart';
|
||||
|
||||
class AuditService {
|
||||
static String get _baseUrl => runtimeBackendUrl();
|
||||
|
||||
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,
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||
debugPrint('Audit log sent successfully');
|
||||
} else {
|
||||
debugPrint(
|
||||
'Failed to send audit log: ${response.statusCode} ${response.body}',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error sending audit log: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
1140
baron-sso/userfront/lib/core/services/auth_proxy_service.dart
Normal file
45
baron-sso/userfront/lib/core/services/auth_token_store.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
import 'auth_token_store_stub.dart'
|
||||
if (dart.library.js_interop) 'auth_token_store_web.dart';
|
||||
|
||||
class AuthTokenStore {
|
||||
static bool hasToken() {
|
||||
final token = getToken();
|
||||
return token != null && token.isNotEmpty;
|
||||
}
|
||||
|
||||
static String? getToken() => authTokenStore.getToken();
|
||||
|
||||
static String? getProvider() => authTokenStore.getProvider();
|
||||
|
||||
static bool usesCookie() => authTokenStore.usesCookie();
|
||||
|
||||
static void setToken(String token, {String? provider}) {
|
||||
authTokenStore.setToken(token, provider: provider);
|
||||
}
|
||||
|
||||
static void setCookieMode({String? provider}) {
|
||||
authTokenStore.setCookieMode(provider: provider);
|
||||
}
|
||||
|
||||
static String? getPendingProvider() => authTokenStore.getPendingProvider();
|
||||
|
||||
static void setPendingProvider(String? provider) {
|
||||
authTokenStore.setPendingProvider(provider);
|
||||
}
|
||||
|
||||
static void clearPendingProvider() {
|
||||
authTokenStore.setPendingProvider(null);
|
||||
}
|
||||
|
||||
static void skipNextCookieSessionCheck() {
|
||||
authTokenStore.skipNextCookieSessionCheck();
|
||||
}
|
||||
|
||||
static bool consumeSkipCookieSessionCheck() {
|
||||
return authTokenStore.consumeSkipCookieSessionCheck();
|
||||
}
|
||||
|
||||
static void clear() {
|
||||
authTokenStore.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
abstract class AuthTokenStorageTarget {
|
||||
String? read(String key);
|
||||
void write(String key, String value);
|
||||
void remove(String key);
|
||||
}
|
||||
|
||||
class AuthTokenStoreBackend {
|
||||
AuthTokenStoreBackend({
|
||||
required AuthTokenStorageTarget localTarget,
|
||||
required AuthTokenStorageTarget sessionTarget,
|
||||
}) : _targets = [localTarget, sessionTarget, _MemoryStorageTarget()];
|
||||
|
||||
static const _tokenKey = 'baron_auth_token';
|
||||
static const _providerKey = 'baron_auth_provider';
|
||||
static const _cookieModeKey = 'baron_auth_cookie_mode';
|
||||
static const _pendingProviderKey = 'baron_auth_pending_provider';
|
||||
static const _skipCookieSessionCheckKey =
|
||||
'baron_auth_skip_cookie_session_check';
|
||||
|
||||
final List<AuthTokenStorageTarget> _targets;
|
||||
|
||||
String? getToken() => _readFirst(_tokenKey);
|
||||
|
||||
String? getProvider() => _readFirst(_providerKey);
|
||||
|
||||
bool usesCookie() => _readFirst(_cookieModeKey) == '1';
|
||||
|
||||
void setToken(String token, {String? provider}) {
|
||||
_writeAll(_tokenKey, token);
|
||||
_removeAll(_cookieModeKey);
|
||||
if (provider != null) {
|
||||
_writeAll(_providerKey, provider);
|
||||
}
|
||||
}
|
||||
|
||||
void setCookieMode({String? provider}) {
|
||||
_writeAll(_cookieModeKey, '1');
|
||||
_removeAll(_tokenKey);
|
||||
if (provider != null) {
|
||||
_writeAll(_providerKey, provider);
|
||||
}
|
||||
}
|
||||
|
||||
String? getPendingProvider() => _readFirst(_pendingProviderKey);
|
||||
|
||||
bool consumeSkipCookieSessionCheck() {
|
||||
final shouldSkip = _readFirst(_skipCookieSessionCheckKey) == '1';
|
||||
if (shouldSkip) {
|
||||
_removeAll(_skipCookieSessionCheckKey);
|
||||
}
|
||||
return shouldSkip;
|
||||
}
|
||||
|
||||
void setPendingProvider(String? provider) {
|
||||
if (provider == null || provider.isEmpty) {
|
||||
_removeAll(_pendingProviderKey);
|
||||
return;
|
||||
}
|
||||
_writeAll(_pendingProviderKey, provider);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_removeAll(_tokenKey);
|
||||
_removeAll(_providerKey);
|
||||
_removeAll(_cookieModeKey);
|
||||
_removeAll(_pendingProviderKey);
|
||||
_removeAll(_skipCookieSessionCheckKey);
|
||||
}
|
||||
|
||||
void skipNextCookieSessionCheck() {
|
||||
_writeAll(_skipCookieSessionCheckKey, '1');
|
||||
}
|
||||
|
||||
String? _readFirst(String key) {
|
||||
for (final target in _targets) {
|
||||
try {
|
||||
final value = target.read(key);
|
||||
if (value != null && value.isNotEmpty) {
|
||||
return value;
|
||||
}
|
||||
} catch (_) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void _writeAll(String key, String value) {
|
||||
for (final target in _targets) {
|
||||
try {
|
||||
target.write(key, value);
|
||||
} catch (_) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _removeAll(String key) {
|
||||
for (final target in _targets) {
|
||||
try {
|
||||
target.remove(key);
|
||||
} catch (_) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _MemoryStorageTarget implements AuthTokenStorageTarget {
|
||||
final Map<String, String> _memory = {};
|
||||
|
||||
@override
|
||||
String? read(String key) => _memory[key];
|
||||
|
||||
@override
|
||||
void remove(String key) {
|
||||
_memory.remove(key);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(String key, String value) {
|
||||
_memory[key] = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
class AuthTokenStore {
|
||||
String? _token;
|
||||
String? _provider;
|
||||
bool _cookieMode = false;
|
||||
String? _pendingProvider;
|
||||
bool _skipCookieSessionCheck = false;
|
||||
|
||||
String? getToken() => _token;
|
||||
|
||||
String? getProvider() => _provider;
|
||||
|
||||
bool usesCookie() => _cookieMode;
|
||||
|
||||
void setToken(String token, {String? provider}) {
|
||||
_token = token;
|
||||
_cookieMode = false;
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
void setCookieMode({String? provider}) {
|
||||
_cookieMode = true;
|
||||
_token = null;
|
||||
if (provider != null) {
|
||||
_provider = provider;
|
||||
}
|
||||
}
|
||||
|
||||
String? getPendingProvider() => _pendingProvider;
|
||||
|
||||
bool consumeSkipCookieSessionCheck() {
|
||||
final shouldSkip = _skipCookieSessionCheck;
|
||||
_skipCookieSessionCheck = false;
|
||||
return shouldSkip;
|
||||
}
|
||||
|
||||
void setPendingProvider(String? provider) {
|
||||
_pendingProvider = provider;
|
||||
}
|
||||
|
||||
void skipNextCookieSessionCheck() {
|
||||
_skipCookieSessionCheck = true;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_token = null;
|
||||
_provider = null;
|
||||
_cookieMode = false;
|
||||
_pendingProvider = null;
|
||||
_skipCookieSessionCheck = false;
|
||||
}
|
||||
}
|
||||
|
||||
final authTokenStore = AuthTokenStore();
|
||||
@@ -0,0 +1,48 @@
|
||||
// ignore_for_file: avoid_web_libraries_in_flutter
|
||||
|
||||
import 'dart:js_interop';
|
||||
import 'auth_token_store_backend.dart';
|
||||
|
||||
@JS('window.localStorage')
|
||||
external _JSStorage get _localStorage;
|
||||
|
||||
@JS('window.sessionStorage')
|
||||
external _JSStorage get _sessionStorage;
|
||||
|
||||
@JS()
|
||||
extension type _JSStorage(JSObject _) implements JSObject {
|
||||
external String? getItem(String key);
|
||||
external void setItem(String key, String value);
|
||||
external void removeItem(String key);
|
||||
}
|
||||
|
||||
class AuthTokenStore extends AuthTokenStoreBackend {
|
||||
AuthTokenStore()
|
||||
: super(
|
||||
localTarget: _JsStorageTarget(_localStorage),
|
||||
sessionTarget: _JsStorageTarget(_sessionStorage),
|
||||
);
|
||||
}
|
||||
|
||||
class _JsStorageTarget implements AuthTokenStorageTarget {
|
||||
_JsStorageTarget(this._storage);
|
||||
|
||||
final _JSStorage _storage;
|
||||
|
||||
@override
|
||||
String? read(String key) {
|
||||
return _storage.getItem(key);
|
||||
}
|
||||
|
||||
@override
|
||||
void remove(String key) {
|
||||
_storage.removeItem(key);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(String key, String value) {
|
||||
_storage.setItem(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
final authTokenStore = AuthTokenStore();
|
||||
6
baron-sso/userfront/lib/core/services/http_client.dart
Normal file
@@ -0,0 +1,6 @@
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'http_client_stub.dart' if (dart.library.html) 'http_client_web.dart';
|
||||
|
||||
http.Client createHttpClient({bool withCredentials = false}) {
|
||||
return httpClientFactory.create(withCredentials: withCredentials);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class HttpClientFactory {
|
||||
http.Client create({bool withCredentials = false}) {
|
||||
return http.Client();
|
||||
}
|
||||
}
|
||||
|
||||
final httpClientFactory = HttpClientFactory();
|
||||
12
baron-sso/userfront/lib/core/services/http_client_web.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
import 'package:http/browser_client.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class HttpClientFactory {
|
||||
http.Client create({bool withCredentials = false}) {
|
||||
final client = BrowserClient();
|
||||
client.withCredentials = withCredentials;
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
final httpClientFactory = HttpClientFactory();
|
||||
139
baron-sso/userfront/lib/core/services/log_policy.dart
Normal file
@@ -0,0 +1,139 @@
|
||||
class LogPolicy {
|
||||
static const Set<String> _sensitiveKeys = {
|
||||
'password',
|
||||
'currentpassword',
|
||||
'newpassword',
|
||||
'oldpassword',
|
||||
'token',
|
||||
'accesstoken',
|
||||
'refreshtoken',
|
||||
'secret',
|
||||
'clientsecret',
|
||||
'authorization',
|
||||
'cookie',
|
||||
'setcookie',
|
||||
'verificationcode',
|
||||
'code',
|
||||
'loginchallenge',
|
||||
'loginverifier',
|
||||
'sessionjwt',
|
||||
'accessjwt',
|
||||
'refreshjwt',
|
||||
};
|
||||
|
||||
static bool isProductionEnv(String? appEnv) {
|
||||
final env = (appEnv ?? '').trim().toLowerCase();
|
||||
return env == 'prod' ||
|
||||
env == 'production' ||
|
||||
env == 'stage' ||
|
||||
env == 'staging';
|
||||
}
|
||||
|
||||
static ({bool enabled, bool specified}) parseOptionalBoolFlag(String? raw) {
|
||||
final value = (raw ?? '').trim().toLowerCase();
|
||||
if (value == '1' ||
|
||||
value == 'true' ||
|
||||
value == 'yes' ||
|
||||
value == 'y' ||
|
||||
value == 'on') {
|
||||
return (enabled: true, specified: true);
|
||||
}
|
||||
if (value == '0' ||
|
||||
value == 'false' ||
|
||||
value == 'no' ||
|
||||
value == 'n' ||
|
||||
value == 'off') {
|
||||
return (enabled: false, specified: true);
|
||||
}
|
||||
return (enabled: false, specified: false);
|
||||
}
|
||||
|
||||
static bool debugEnabled({
|
||||
required String? appEnv,
|
||||
required String? productionDebugFlag,
|
||||
}) {
|
||||
if (!isProductionEnv(appEnv)) {
|
||||
return true;
|
||||
}
|
||||
final flag = parseOptionalBoolFlag(productionDebugFlag);
|
||||
return flag.specified && flag.enabled;
|
||||
}
|
||||
|
||||
static bool shouldRelayClientLog({
|
||||
required String level,
|
||||
required String? appEnv,
|
||||
required String? productionDebugFlag,
|
||||
}) {
|
||||
final flag = parseOptionalBoolFlag(productionDebugFlag);
|
||||
final debugRelayEnabled = isProductionEnv(appEnv)
|
||||
? flag.specified && flag.enabled
|
||||
: !(flag.specified && !flag.enabled);
|
||||
|
||||
if (debugRelayEnabled) {
|
||||
return true;
|
||||
}
|
||||
final normalized = level.trim().toUpperCase();
|
||||
return normalized == 'SEVERE' ||
|
||||
normalized == 'ERROR' ||
|
||||
normalized == 'WARNING' ||
|
||||
normalized == 'WARN';
|
||||
}
|
||||
|
||||
static String sanitizeMessage(String message) {
|
||||
if (message.trim().isEmpty) {
|
||||
return message;
|
||||
}
|
||||
var sanitized = message.replaceAllMapped(
|
||||
RegExp(
|
||||
r'"(password|currentpassword|newpassword|oldpassword|token|accesstoken|refreshtoken|secret|clientsecret|authorization|cookie|setcookie|verificationcode|code|loginchallenge|loginverifier|sessionjwt|accessjwt|refreshjwt)"\s*:\s*"[^"]*"',
|
||||
caseSensitive: false,
|
||||
),
|
||||
(match) {
|
||||
final key = match.group(1) ?? 'sensitive';
|
||||
return '"$key":"*****"';
|
||||
},
|
||||
);
|
||||
sanitized = sanitized.replaceAllMapped(
|
||||
RegExp(
|
||||
r'\b(password|current_password|currentpassword|new_password|newpassword|old_password|oldpassword|token|access_token|accesstoken|refresh_token|refreshtoken|authorization|cookie|session_jwt|sessionjwt|access_jwt|accessjwt|refresh_jwt|refreshjwt)\b\s*[:=]\s*([^\s,;]+)',
|
||||
caseSensitive: false,
|
||||
),
|
||||
(match) {
|
||||
final key = match.group(1) ?? 'sensitive';
|
||||
return '$key=*****';
|
||||
},
|
||||
);
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
static Map<String, dynamic> sanitizeData(Map<String, dynamic> input) {
|
||||
final output = <String, dynamic>{};
|
||||
for (final entry in input.entries) {
|
||||
if (_isSensitiveKey(entry.key)) {
|
||||
output[entry.key] = '*****';
|
||||
} else {
|
||||
output[entry.key] = _sanitizeValue(entry.value);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
static dynamic _sanitizeValue(dynamic value) {
|
||||
if (value is Map<String, dynamic>) {
|
||||
return sanitizeData(value);
|
||||
}
|
||||
if (value is List) {
|
||||
return value.map(_sanitizeValue).toList(growable: false);
|
||||
}
|
||||
if (value is String) {
|
||||
return sanitizeMessage(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool _isSensitiveKey(String key) {
|
||||
var normalized = key.trim().toLowerCase();
|
||||
normalized = normalized.replaceAll(RegExp(r'[-_.\s]'), '');
|
||||
return _sensitiveKeys.contains(normalized);
|
||||
}
|
||||
}
|
||||
111
baron-sso/userfront/lib/core/services/logger_service.dart
Normal file
@@ -0,0 +1,111 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:logging/logging.dart' as std_log;
|
||||
import 'package:logger/logger.dart' as pretty_log;
|
||||
import 'auth_proxy_service.dart';
|
||||
import 'log_policy.dart';
|
||||
import 'runtime_env.dart';
|
||||
|
||||
/// Global Logger Service for Baron SSO Frontend
|
||||
class LoggerService {
|
||||
static final LoggerService _instance = LoggerService._internal();
|
||||
factory LoggerService() => _instance;
|
||||
|
||||
late final pretty_log.Logger _prettyLogger;
|
||||
late final String _appEnv;
|
||||
late final String _productionDebugFlag;
|
||||
|
||||
LoggerService._internal() {
|
||||
_appEnv = envOrDefault('APP_ENV', 'dev');
|
||||
_productionDebugFlag = envOrDefault(
|
||||
'CLIENT_LOG_DEBUG',
|
||||
envOrDefault('USERFRONT_DEBUG_LOG', ''),
|
||||
);
|
||||
final debugEnabled = LogPolicy.debugEnabled(
|
||||
appEnv: _appEnv,
|
||||
productionDebugFlag: _productionDebugFlag,
|
||||
);
|
||||
|
||||
// 1. Initialize Pretty Logger for Dev
|
||||
_prettyLogger = pretty_log.Logger(
|
||||
printer: pretty_log.PrettyPrinter(
|
||||
methodCount: 0,
|
||||
errorMethodCount: 8,
|
||||
lineLength: 120,
|
||||
colors: true,
|
||||
printEmojis: true,
|
||||
dateTimeFormat: pretty_log.DateTimeFormat.onlyTimeAndSinceStart,
|
||||
),
|
||||
);
|
||||
|
||||
// 2. Configure Standard Logger (logging package)
|
||||
std_log.Logger.root.level = debugEnabled
|
||||
? std_log.Level.ALL
|
||||
: std_log.Level.WARNING;
|
||||
|
||||
std_log.Logger.root.onRecord.listen((record) {
|
||||
if (kReleaseMode) {
|
||||
// [Production] Log as JSON
|
||||
_logJson(record);
|
||||
} else {
|
||||
// [Development] Log using Pretty Printer
|
||||
_logPretty(record);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Initialize the logger. Call this in main.dart
|
||||
static void init() {
|
||||
// Accessing the instance triggers the constructor
|
||||
LoggerService();
|
||||
std_log.Logger('BaronSSO').info('Logger initialized');
|
||||
}
|
||||
|
||||
void _logPretty(std_log.LogRecord record) {
|
||||
if (record.level >= std_log.Level.SEVERE) {
|
||||
_prettyLogger.e(
|
||||
record.message,
|
||||
error: record.error,
|
||||
stackTrace: record.stackTrace,
|
||||
);
|
||||
} else if (record.level >= std_log.Level.WARNING) {
|
||||
_prettyLogger.w(record.message);
|
||||
} else if (record.level >= std_log.Level.INFO) {
|
||||
_prettyLogger.i(record.message);
|
||||
} else {
|
||||
_prettyLogger.d(record.message);
|
||||
}
|
||||
}
|
||||
|
||||
void _logJson(std_log.LogRecord record) {
|
||||
final sanitizedMessage = LogPolicy.sanitizeMessage(record.message);
|
||||
final logData = {
|
||||
'time': record.time.toUtc().toIso8601String(), // Use UTC for consistency
|
||||
'level': record.level.name,
|
||||
'msg': sanitizedMessage,
|
||||
'svc': 'baron-userfront',
|
||||
if (record.error != null) 'error': record.error.toString(),
|
||||
if (record.stackTrace != null) 'stack': record.stackTrace.toString(),
|
||||
};
|
||||
|
||||
// 1. Print to Browser Console (F12)
|
||||
debugPrint(jsonEncode(logData));
|
||||
|
||||
// 2. Relay to Backend (Docker Terminal)
|
||||
if (LogPolicy.shouldRelayClientLog(
|
||||
level: record.level.name,
|
||||
appEnv: _appEnv,
|
||||
productionDebugFlag: _productionDebugFlag,
|
||||
)) {
|
||||
AuthProxyService.sendLog(
|
||||
record.level.name,
|
||||
sanitizedMessage,
|
||||
data: {
|
||||
'client_time': record.time.toUtc().toIso8601String(),
|
||||
'logger': record.loggerName,
|
||||
if (record.error != null) 'error': record.error.toString(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import 'login_challenge_loop_guard_stub.dart'
|
||||
if (dart.library.js_interop) 'login_challenge_loop_guard_web.dart';
|
||||
|
||||
final loginChallengeLoopGuard = createLoginChallengeLoopGuard();
|
||||
@@ -0,0 +1,5 @@
|
||||
abstract class LoginChallengeLoopGuard {
|
||||
bool shouldAllowAutoAccept(String loginChallenge, {int cooldownMs = 15000});
|
||||
void markAutoAcceptAttempt(String loginChallenge);
|
||||
void clear(String loginChallenge);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import 'login_challenge_loop_guard_base.dart';
|
||||
|
||||
class _InMemoryLoginChallengeLoopGuard implements LoginChallengeLoopGuard {
|
||||
final Map<String, int> _lastAttemptAtMs = <String, int>{};
|
||||
|
||||
@override
|
||||
bool shouldAllowAutoAccept(String loginChallenge, {int cooldownMs = 15000}) {
|
||||
final challenge = loginChallenge.trim();
|
||||
if (challenge.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
final nowMs = DateTime.now().millisecondsSinceEpoch;
|
||||
final lastMs = _lastAttemptAtMs[challenge];
|
||||
if (lastMs == null) {
|
||||
return true;
|
||||
}
|
||||
return nowMs - lastMs > cooldownMs;
|
||||
}
|
||||
|
||||
@override
|
||||
void markAutoAcceptAttempt(String loginChallenge) {
|
||||
final challenge = loginChallenge.trim();
|
||||
if (challenge.isEmpty) {
|
||||
return;
|
||||
}
|
||||
_lastAttemptAtMs[challenge] = DateTime.now().millisecondsSinceEpoch;
|
||||
}
|
||||
|
||||
@override
|
||||
void clear(String loginChallenge) {
|
||||
_lastAttemptAtMs.remove(loginChallenge.trim());
|
||||
}
|
||||
}
|
||||
|
||||
LoginChallengeLoopGuard createLoginChallengeLoopGuard() {
|
||||
return _InMemoryLoginChallengeLoopGuard();
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// ignore_for_file: avoid_web_libraries_in_flutter
|
||||
|
||||
import 'dart:js_interop';
|
||||
import 'login_challenge_loop_guard_base.dart';
|
||||
|
||||
@JS('window.sessionStorage')
|
||||
external _JSStorage get _sessionStorage;
|
||||
|
||||
@JS()
|
||||
extension type _JSStorage(JSObject _) implements JSObject {
|
||||
external String? getItem(String key);
|
||||
external void setItem(String key, String value);
|
||||
external void removeItem(String key);
|
||||
}
|
||||
|
||||
class _WebLoginChallengeLoopGuard implements LoginChallengeLoopGuard {
|
||||
static const String _keyPrefix = 'baron_oidc_auto_accept_last:';
|
||||
|
||||
String _key(String challenge) => '$_keyPrefix$challenge';
|
||||
|
||||
@override
|
||||
bool shouldAllowAutoAccept(String loginChallenge, {int cooldownMs = 15000}) {
|
||||
final challenge = loginChallenge.trim();
|
||||
if (challenge.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
final raw = _sessionStorage.getItem(_key(challenge));
|
||||
if (raw == null || raw.isEmpty) {
|
||||
return true;
|
||||
}
|
||||
final lastMs = int.tryParse(raw);
|
||||
if (lastMs == null) {
|
||||
return true;
|
||||
}
|
||||
final nowMs = DateTime.now().millisecondsSinceEpoch;
|
||||
return nowMs - lastMs > cooldownMs;
|
||||
} catch (_) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void markAutoAcceptAttempt(String loginChallenge) {
|
||||
final challenge = loginChallenge.trim();
|
||||
if (challenge.isEmpty) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final nowMs = DateTime.now().millisecondsSinceEpoch;
|
||||
_sessionStorage.setItem(_key(challenge), nowMs.toString());
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
@override
|
||||
void clear(String loginChallenge) {
|
||||
final challenge = loginChallenge.trim();
|
||||
if (challenge.isEmpty) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
_sessionStorage.removeItem(_key(challenge));
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
LoginChallengeLoopGuard createLoginChallengeLoopGuard() {
|
||||
return _WebLoginChallengeLoopGuard();
|
||||
}
|
||||
39
baron-sso/userfront/lib/core/services/logout_service.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
import '../notifiers/auth_notifier.dart';
|
||||
import 'auth_proxy_service.dart';
|
||||
import 'auth_token_store.dart';
|
||||
|
||||
typedef CurrentSessionLoader = Future<String?> Function();
|
||||
typedef SessionRevoker = Future<void> Function(String sessionId);
|
||||
typedef LogoutCallback = void Function();
|
||||
|
||||
class LogoutService {
|
||||
LogoutService({
|
||||
CurrentSessionLoader? loadCurrentSessionId,
|
||||
SessionRevoker? revokeSession,
|
||||
LogoutCallback? clearAuth,
|
||||
LogoutCallback? notifyAuthChanged,
|
||||
}) : _loadCurrentSessionId =
|
||||
loadCurrentSessionId ?? AuthProxyService.fetchCurrentSessionId,
|
||||
_revokeSession = revokeSession ?? AuthProxyService.revokeSession,
|
||||
_clearAuth = clearAuth ?? AuthTokenStore.clear,
|
||||
_notifyAuthChanged = notifyAuthChanged ?? AuthNotifier.instance.notify;
|
||||
|
||||
final CurrentSessionLoader _loadCurrentSessionId;
|
||||
final SessionRevoker _revokeSession;
|
||||
final LogoutCallback _clearAuth;
|
||||
final LogoutCallback _notifyAuthChanged;
|
||||
|
||||
Future<void> logout() async {
|
||||
try {
|
||||
final currentSessionId = await _loadCurrentSessionId();
|
||||
if (currentSessionId != null && currentSessionId.isNotEmpty) {
|
||||
await _revokeSession(currentSessionId);
|
||||
}
|
||||
} catch (_) {
|
||||
// 서버 세션 종료는 best-effort로 처리하고, 로컬 로그아웃은 계속 진행합니다.
|
||||
} finally {
|
||||
_clearAuth();
|
||||
_notifyAuthChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import '../i18n/locale_utils.dart';
|
||||
|
||||
String? computeNullCheckRecoveryTarget({
|
||||
required Object exception,
|
||||
required Uri uri,
|
||||
required String preferredLocaleCode,
|
||||
}) {
|
||||
final message = exception.toString();
|
||||
if (!message.contains('Null check operator used on a null value')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final localeCode =
|
||||
extractLocaleFromPath(uri) ?? normalizeLocaleCode(preferredLocaleCode);
|
||||
final path = uri.path;
|
||||
final localeRootPath = '/$localeCode';
|
||||
if (path != '/' && path != localeRootPath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final target = '/$localeCode/signin';
|
||||
if (path == target) {
|
||||
return null;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
220
baron-sso/userfront/lib/core/services/oidc_redirect_guard.dart
Normal file
@@ -0,0 +1,220 @@
|
||||
class OidcRedirectCheckResult {
|
||||
final Uri? uri;
|
||||
final bool isValid;
|
||||
final String reason;
|
||||
final int length;
|
||||
final String scheme;
|
||||
final String host;
|
||||
final String path;
|
||||
final int queryParamCount;
|
||||
final List<String> queryKeys;
|
||||
final bool hasLoginVerifier;
|
||||
final int loginVerifierLength;
|
||||
final bool hasState;
|
||||
final int stateLength;
|
||||
final bool hasClientId;
|
||||
final String clientId;
|
||||
final bool hasCodeChallenge;
|
||||
final int codeChallengeLength;
|
||||
final String codeChallengeMethod;
|
||||
final bool hasRedirectUri;
|
||||
final int redirectUriLength;
|
||||
final String redirectUriScheme;
|
||||
final String redirectUriHost;
|
||||
final int redirectUriPort;
|
||||
final String redirectUriPath;
|
||||
final String responseType;
|
||||
final int scopeCount;
|
||||
final bool isOidcAuthPath;
|
||||
|
||||
const OidcRedirectCheckResult({
|
||||
required this.uri,
|
||||
required this.isValid,
|
||||
required this.reason,
|
||||
required this.length,
|
||||
required this.scheme,
|
||||
required this.host,
|
||||
required this.path,
|
||||
required this.queryParamCount,
|
||||
required this.queryKeys,
|
||||
required this.hasLoginVerifier,
|
||||
required this.loginVerifierLength,
|
||||
required this.hasState,
|
||||
required this.stateLength,
|
||||
required this.hasClientId,
|
||||
required this.clientId,
|
||||
required this.hasCodeChallenge,
|
||||
required this.codeChallengeLength,
|
||||
required this.codeChallengeMethod,
|
||||
required this.hasRedirectUri,
|
||||
required this.redirectUriLength,
|
||||
required this.redirectUriScheme,
|
||||
required this.redirectUriHost,
|
||||
required this.redirectUriPort,
|
||||
required this.redirectUriPath,
|
||||
required this.responseType,
|
||||
required this.scopeCount,
|
||||
required this.isOidcAuthPath,
|
||||
});
|
||||
|
||||
Map<String, Object?> toDiagnostics() {
|
||||
return {
|
||||
'is_valid': isValid,
|
||||
'reason': reason,
|
||||
'length': length,
|
||||
'scheme': scheme,
|
||||
'host': host,
|
||||
'path': path,
|
||||
'is_oidc_auth_path': isOidcAuthPath,
|
||||
'query_param_count': queryParamCount,
|
||||
'query_keys': queryKeys,
|
||||
'has_login_verifier': hasLoginVerifier,
|
||||
'login_verifier_len': loginVerifierLength,
|
||||
'has_state': hasState,
|
||||
'state_len': stateLength,
|
||||
'has_client_id': hasClientId,
|
||||
'client_id': clientId,
|
||||
'has_code_challenge': hasCodeChallenge,
|
||||
'code_challenge_len': codeChallengeLength,
|
||||
'code_challenge_method': codeChallengeMethod,
|
||||
'has_redirect_uri': hasRedirectUri,
|
||||
'redirect_uri_len': redirectUriLength,
|
||||
'redirect_uri_scheme': redirectUriScheme,
|
||||
'redirect_uri_host': redirectUriHost,
|
||||
'redirect_uri_port': redirectUriPort,
|
||||
'redirect_uri_path': redirectUriPath,
|
||||
'response_type': responseType,
|
||||
'scope_count': scopeCount,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
OidcRedirectCheckResult validateOidcRedirectTarget(String redirectTo) {
|
||||
final trimmed = redirectTo.trim();
|
||||
if (trimmed.isEmpty) {
|
||||
return const OidcRedirectCheckResult(
|
||||
uri: null,
|
||||
isValid: false,
|
||||
reason: 'empty',
|
||||
length: 0,
|
||||
scheme: '',
|
||||
host: '',
|
||||
path: '',
|
||||
queryParamCount: 0,
|
||||
queryKeys: [],
|
||||
hasLoginVerifier: false,
|
||||
loginVerifierLength: 0,
|
||||
hasState: false,
|
||||
stateLength: 0,
|
||||
hasClientId: false,
|
||||
clientId: '',
|
||||
hasCodeChallenge: false,
|
||||
codeChallengeLength: 0,
|
||||
codeChallengeMethod: '',
|
||||
hasRedirectUri: false,
|
||||
redirectUriLength: 0,
|
||||
redirectUriScheme: '',
|
||||
redirectUriHost: '',
|
||||
redirectUriPort: 0,
|
||||
redirectUriPath: '',
|
||||
responseType: '',
|
||||
scopeCount: 0,
|
||||
isOidcAuthPath: false,
|
||||
);
|
||||
}
|
||||
|
||||
Uri parsed;
|
||||
try {
|
||||
parsed = Uri.parse(trimmed);
|
||||
} catch (_) {
|
||||
return OidcRedirectCheckResult(
|
||||
uri: null,
|
||||
isValid: false,
|
||||
reason: 'parse_error',
|
||||
length: trimmed.length,
|
||||
scheme: '',
|
||||
host: '',
|
||||
path: '',
|
||||
queryParamCount: 0,
|
||||
queryKeys: [],
|
||||
hasLoginVerifier: false,
|
||||
loginVerifierLength: 0,
|
||||
hasState: false,
|
||||
stateLength: 0,
|
||||
hasClientId: false,
|
||||
clientId: '',
|
||||
hasCodeChallenge: false,
|
||||
codeChallengeLength: 0,
|
||||
codeChallengeMethod: '',
|
||||
hasRedirectUri: false,
|
||||
redirectUriLength: 0,
|
||||
redirectUriScheme: '',
|
||||
redirectUriHost: '',
|
||||
redirectUriPort: 0,
|
||||
redirectUriPath: '',
|
||||
responseType: '',
|
||||
scopeCount: 0,
|
||||
isOidcAuthPath: false,
|
||||
);
|
||||
}
|
||||
|
||||
final scheme = parsed.scheme.toLowerCase();
|
||||
final isHttpScheme = scheme == 'http' || scheme == 'https';
|
||||
final isAbsolute = parsed.hasScheme && parsed.host.isNotEmpty;
|
||||
final isValid = isHttpScheme && isAbsolute;
|
||||
final query = parsed.queryParameters;
|
||||
final queryKeys = query.keys.toList()..sort();
|
||||
final loginVerifier = query['login_verifier'] ?? '';
|
||||
final state = query['state'] ?? '';
|
||||
final clientId = query['client_id'] ?? '';
|
||||
final codeChallenge = query['code_challenge'] ?? '';
|
||||
final codeChallengeMethod = query['code_challenge_method'] ?? '';
|
||||
final redirectUriValue = query['redirect_uri'] ?? query['redirect_url'] ?? '';
|
||||
final responseType = query['response_type'] ?? '';
|
||||
final scope = query['scope'] ?? '';
|
||||
|
||||
final Uri? redirectUriParsed = redirectUriValue.isEmpty
|
||||
? null
|
||||
: Uri.tryParse(redirectUriValue);
|
||||
final redirectUriScheme = redirectUriParsed?.scheme ?? '';
|
||||
final redirectUriHost = redirectUriParsed?.host ?? '';
|
||||
final redirectUriPort = redirectUriParsed?.port ?? 0;
|
||||
final redirectUriPath = redirectUriParsed?.path ?? '';
|
||||
final scopeCount = scope.isEmpty
|
||||
? 0
|
||||
: scope.split(RegExp(r'\s+')).where((s) => s.isNotEmpty).length;
|
||||
|
||||
final reason = isValid
|
||||
? 'ok'
|
||||
: (isAbsolute ? 'unsupported_scheme' : 'not_absolute');
|
||||
|
||||
return OidcRedirectCheckResult(
|
||||
uri: isValid ? parsed : null,
|
||||
isValid: isValid,
|
||||
reason: reason,
|
||||
length: trimmed.length,
|
||||
scheme: scheme,
|
||||
host: parsed.host,
|
||||
path: parsed.path,
|
||||
queryParamCount: query.length,
|
||||
queryKeys: queryKeys,
|
||||
hasLoginVerifier: loginVerifier.isNotEmpty,
|
||||
loginVerifierLength: loginVerifier.length,
|
||||
hasState: state.isNotEmpty,
|
||||
stateLength: state.length,
|
||||
hasClientId: clientId.isNotEmpty,
|
||||
clientId: clientId,
|
||||
hasCodeChallenge: codeChallenge.isNotEmpty,
|
||||
codeChallengeLength: codeChallenge.length,
|
||||
codeChallengeMethod: codeChallengeMethod,
|
||||
hasRedirectUri: redirectUriValue.isNotEmpty,
|
||||
redirectUriLength: redirectUriValue.length,
|
||||
redirectUriScheme: redirectUriScheme,
|
||||
redirectUriHost: redirectUriHost,
|
||||
redirectUriPort: redirectUriPort,
|
||||
redirectUriPath: redirectUriPath,
|
||||
responseType: responseType,
|
||||
scopeCount: scopeCount,
|
||||
isOidcAuthPath: parsed.path == '/oidc/oauth2/auth',
|
||||
);
|
||||
}
|
||||
37
baron-sso/userfront/lib/core/services/runtime_env.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
const _compileTimeEnv = {
|
||||
'APP_ENV': String.fromEnvironment('APP_ENV'),
|
||||
'BACKEND_URL': String.fromEnvironment('BACKEND_URL'),
|
||||
'CLIENT_LOG_DEBUG': String.fromEnvironment('CLIENT_LOG_DEBUG'),
|
||||
'USERFRONT_DEBUG_LOG': String.fromEnvironment('USERFRONT_DEBUG_LOG'),
|
||||
'USERFRONT_URL': String.fromEnvironment('USERFRONT_URL'),
|
||||
};
|
||||
|
||||
String runtimeOriginFallback() {
|
||||
try {
|
||||
final origin = Uri.base.origin;
|
||||
if (origin.isNotEmpty && origin != 'null') {
|
||||
return origin;
|
||||
}
|
||||
} catch (_) {}
|
||||
return '';
|
||||
}
|
||||
|
||||
String envOrDefault(String key, String fallback) {
|
||||
final compileTimeValue = _compileTimeEnv[key];
|
||||
if (compileTimeValue != null && compileTimeValue.trim().isNotEmpty) {
|
||||
return compileTimeValue;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import 'web_auth_integration_stub.dart'
|
||||
if (dart.library.js_interop) 'web_auth_integration_web.dart';
|
||||
|
||||
abstract class WebAuthIntegration {
|
||||
static void sendLoginSuccess(String token) {
|
||||
// Platform-specific implementation
|
||||
implSendLoginSuccess(token);
|
||||
}
|
||||
|
||||
static bool isPopup() {
|
||||
return implIsPopup();
|
||||
}
|
||||
}
|
||||