diff --git a/Makefile b/Makefile index 87e0a8f0..0eea204a 100644 --- a/Makefile +++ b/Makefile @@ -265,7 +265,9 @@ code-check-userfront-e2e-tests: (cd "$$tmp_dir/userfront-e2e" && $(PLAYWRIGHT_INSTALL_CHROMIUM)) || status=$$?; \ fi; \ if [ $$status -eq 0 ]; then \ - (cd "$$tmp_dir/userfront-e2e" && npm test) || status=$$?; \ + port="$$(node -e "const net=require('node:net'); const s=net.createServer(); s.listen(0,'127.0.0.1',()=>{console.log(s.address().port); s.close();});")"; \ + echo "==> userfront-e2e using PORT=$$port"; \ + (cd "$$tmp_dir/userfront-e2e" && PORT=$$port npm test) || status=$$?; \ fi; \ [ -d "$$tmp_dir/userfront-e2e/playwright-report" ] && cp -R "$$tmp_dir/userfront-e2e/playwright-report" reports/userfront-e2e/ || true; \ [ -d "$$tmp_dir/userfront-e2e/test-results" ] && cp -R "$$tmp_dir/userfront-e2e/test-results" reports/userfront-e2e/ || true; \ diff --git a/devfront/src/components/layout/AppLayout.tsx b/devfront/src/components/layout/AppLayout.tsx index a5163929..c0324ac1 100644 --- a/devfront/src/components/layout/AppLayout.tsx +++ b/devfront/src/components/layout/AppLayout.tsx @@ -211,11 +211,11 @@ function AppLayout() {
-

{t("msg.dev.sidebar.notice", "개발자 전용 콘솔입니다.")}

+

{t("msg.dev.sidebar.notice", "Developer Console")}

{t( "msg.dev.sidebar.notice_detail", - "클라이언트 애플리케이션 등록 및 관리를 수행할 수 있습니다.", + "Register and manage client applications.", )}

@@ -299,11 +299,17 @@ function AppLayout() { disabled={isRefreshingSession} > {isRefreshingSession - ? t( - "ui.dev.session.refreshing", - "세션 만료 시간 갱신 중...", - ) - : t("ui.dev.session.refresh", "세션 만료 시간 갱신")} + ? t("ui.dev.session.refreshing", "Refreshing...") + : t("ui.dev.session.refresh", "Refresh session expiry")} + + ) : null} diff --git a/devfront/src/components/ui/badge.tsx b/devfront/src/components/ui/badge.tsx index 8ef586fd..97aa8bf9 100644 --- a/devfront/src/components/ui/badge.tsx +++ b/devfront/src/components/ui/badge.tsx @@ -17,6 +17,7 @@ const badgeVariants = cva( "border-transparent bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300", warning: "border-transparent bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-200", + info: "border-transparent bg-blue-500 text-white hover:bg-blue-500/90", }, }, defaultVariants: { diff --git a/devfront/src/features/clients/ClientConsentsPage.tsx b/devfront/src/features/clients/ClientConsentsPage.tsx index 1f44f2f6..c6f3d108 100644 --- a/devfront/src/features/clients/ClientConsentsPage.tsx +++ b/devfront/src/features/clients/ClientConsentsPage.tsx @@ -34,8 +34,8 @@ function ClientConsentsPage() { const clientId = params.id ?? ""; const [subjectInput, setSubjectInput] = useState(""); const [subject, setSubject] = useState(""); - const [statusFilter, setStatusFilter] = useState("all"); - const [scopeFilter, setScopeFilter] = useState("all"); + const [statusFilter, setStatusFilter] = useState([]); + const [scopeFilter, setScopeFilter] = useState([]); const [isAdvancedFilterOpen, setIsAdvancedFilterOpen] = useState(false); const { data: clientData } = useQuery({ @@ -49,8 +49,8 @@ function ClientConsentsPage() { error, refetch, } = useQuery({ - queryKey: ["consents", clientId, subject, statusFilter], - queryFn: () => fetchConsents(subject, clientId, statusFilter), + queryKey: ["consents", clientId, subject], + queryFn: () => fetchConsents(subject, clientId, "all"), enabled: clientId.length > 0, }); const revokeMutation = useMutation({ @@ -77,7 +77,12 @@ function ClientConsentsPage() { const rows = consentsData?.items ?? []; const allScopes = Array.from(new Set(rows.flatMap((r) => r.grantedScopes))); const filteredRows = rows.filter((row) => { - return scopeFilter === "all" || row.grantedScopes.includes(scopeFilter); + const matchStatus = + statusFilter.length === 0 || statusFilter.includes(row.status); + const matchScope = + scopeFilter.length === 0 || + scopeFilter.some((s) => row.grantedScopes.includes(s)); + return matchStatus && matchScope; }); const handleExportCSV = () => { @@ -130,6 +135,30 @@ function ClientConsentsPage() { document.body.removeChild(link); }; + const handleStatusFilterChange = (status: string, checked: boolean) => { + if (checked) { + setStatusFilter((prev) => [...prev, status]); + } else { + setStatusFilter((prev) => prev.filter((s) => s !== status)); + } + }; + + const handleScopeFilterChange = (scope: string, checked: boolean) => { + if (checked) { + setScopeFilter((prev) => [...prev, scope]); + } else { + setScopeFilter((prev) => prev.filter((s) => s !== scope)); + } + }; + + const handleAllScopesChange = (checked: boolean) => { + if (checked) { + setScopeFilter(allScopes); + } else { + setScopeFilter([]); + } + }; + return (
@@ -175,7 +204,7 @@ function ClientConsentsPage() {
{clientData?.client?.status === "active" @@ -252,59 +281,90 @@ function ClientConsentsPage() {
{isAdvancedFilterOpen && ( -
-
- +
+
+ {t("ui.dev.clients.consents.status_label", "Status:")} - + handleStatusFilterChange("active", e.target.checked) + } + /> {t("ui.common.status.active", "Active")} - - - + +
-
- +
+ {t("ui.dev.clients.consents.scope_label", "Scope:")} - 0 + } + onChange={(e) => + handleAllScopesChange(e.target.checked) + } + /> + ALL + + )} {allScopes.map((scope) => ( - + ))} - +
- +
+ +
)} diff --git a/devfront/src/features/clients/ClientDetailsPage.tsx b/devfront/src/features/clients/ClientDetailsPage.tsx index a372fef0..1fa793c6 100644 --- a/devfront/src/features/clients/ClientDetailsPage.tsx +++ b/devfront/src/features/clients/ClientDetailsPage.tsx @@ -1,6 +1,14 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { AxiosError } from "axios"; -import { Eye, EyeOff, Link2, RefreshCw, Save, Shield } from "lucide-react"; +import { + ArrowLeft, + Eye, + EyeOff, + Link2, + RefreshCw, + Save, + Shield, +} from "lucide-react"; import { useEffect, useState } from "react"; import { Link, useParams } from "react-router-dom"; import { Badge } from "../../components/ui/badge"; @@ -183,29 +191,42 @@ function ClientDetailsPage() { return (
-
- - {t("ui.dev.clients.details.breadcrumb.section", "Apps")} +
+
-
-

- {data.client.name || data.client.id} -

-

- {t( - "msg.dev.clients.details.subtitle", - "OIDC 자격 증명과 엔드포인트를 관리합니다.", - )} -

+
+ +
+

+ {data.client.name || data.client.id} +

+

+ {t( + "msg.dev.clients.details.subtitle", + "Manage OIDC credentials and endpoints.", + )} +

+
{data.client.status === "active" @@ -241,7 +262,7 @@ function ClientDetailsPage() {

{t( "ui.dev.clients.details.credentials.title", - "클라이언트 자격 증명", + "Client Credentials", )}

diff --git a/devfront/src/features/clients/ClientGeneralPage.tsx b/devfront/src/features/clients/ClientGeneralPage.tsx index 349bba58..91bcd6cc 100644 --- a/devfront/src/features/clients/ClientGeneralPage.tsx +++ b/devfront/src/features/clients/ClientGeneralPage.tsx @@ -1,6 +1,14 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { AxiosError } from "axios"; -import { Plus, Save, Shield, Sparkles, Trash2, Upload } from "lucide-react"; +import { + ArrowLeft, + Plus, + Save, + Shield, + Sparkles, + Trash2, + Upload, +} from "lucide-react"; import { useEffect, useState } from "react"; import { Link, useNavigate, useParams } from "react-router-dom"; import { Badge } from "../../components/ui/badge"; @@ -261,22 +269,41 @@ function ClientGeneralPage() {
-
- - {t("ui.dev.clients.general.breadcrumb.section", "Applications")} + +
+ +

+ {isCreate + ? t("ui.dev.clients.general.title_create", "Create Client") + : t("ui.dev.clients.general.title_edit", "Client Settings")} +

-

- {isCreate - ? t("ui.dev.clients.general.title_create", "Create Client") - : t("ui.dev.clients.general.title_edit", "Client Settings")} -

{!isCreate && ( {status === "active" @@ -292,7 +319,7 @@ function ClientGeneralPage() { to={`/clients/${clientId}`} className="whitespace-nowrap border-b-2 border-transparent text-muted-foreground hover:text-foreground" > - {t("ui.dev.clients.details.tab.connection", "Connection")} + {t("ui.dev.clients.details.tab.connection", "Federation")} {client.status === "active" diff --git a/devfront/src/features/clients/routes/ClientFederationPage.tsx b/devfront/src/features/clients/routes/ClientFederationPage.tsx index c61c20be..6700e7fe 100644 --- a/devfront/src/features/clients/routes/ClientFederationPage.tsx +++ b/devfront/src/features/clients/routes/ClientFederationPage.tsx @@ -267,7 +267,7 @@ export function ClientFederationPage() { diff --git a/devfront/src/locales/en.toml b/devfront/src/locales/en.toml index 45da9846..dcceb9bf 100644 --- a/devfront/src/locales/en.toml +++ b/devfront/src/locales/en.toml @@ -227,25 +227,25 @@ subtitle = "Subtitle" [msg.dev.clients.details] copy_client_id = "Client ID copied." -copy_client_secret = "Copy Client Secret" +copy_client_secret = "Client Secret copied." copy_endpoint = "{{label}} copied." load_error = "Error loading client: {{error}}" loading = "Loading client..." missing_id = "Client ID is required." redirect_saved = "Redirect URIs saved." -rotate_confirm = "Rotate Confirm" -rotate_error = "Rotate Error" -save_error = "Save Error" -secret_rotated = "Secret Rotated" +rotate_confirm = "Warning: Rotating the Client Secret will invalidate the existing secret immediately.\nConnected applications may experience downtime. Do you want to proceed?" +rotate_error = "Failed to rotate secret: {{error}}" +save_error = "Failed to save: {{error}}" +secret_rotated = "Client Secret has been rotated." secret_unavailable = "SECRET_NOT_AVAILABLE" -subtitle = "Subtitle" +subtitle = "Manage OIDC credentials and endpoints." [msg.dev.clients.details.redirect] -description = "Description" +description = "A list of allowed URLs to redirect users to after successful authentication. You can enter multiple URLs separated by commas." [msg.dev.clients.details.security] -footer = "Footer" -note = "Note" +footer = "We recommend verifying admin session TTL, applying rate limits, and setting up notifications for secret rotation." +note = "Keep endpoints read-only and ensure that secret rotation and copying are tracked in audit logs." [msg.dev.clients.general] load_error = "Error loading client: {{error}}" @@ -301,8 +301,8 @@ dev_scope = "Dev Scope" hydra_health = "Hydra Health" [msg.dev.sidebar] -notice = "Notice" -notice_detail = "Notice Detail" +notice = "Developer Console" +notice_detail = "Register and manage client applications." [msg.info] saved_success = "Saved successfully." @@ -978,6 +978,13 @@ active_grants = "Active Grants" avg_scopes = "Avg. Scopes per User" total_scopes = "Total Scopes Issued" +[ui.dev.clients.stats] +total = "Total Applications" +active_sessions = "Active Sessions" +auth_failures = "Auth Failures (24h)" +realtime = "Realtime" +stable = "Stable" + [ui.dev.clients.consents.table] action = "Action" first_granted = "First Granted" @@ -990,24 +997,24 @@ user = "User" [ui.dev.clients.details] [ui.dev.clients.details.breadcrumb] -current = "Current" -section = "Applications" +current = "App Details" +section = "Connected Applications" [ui.dev.clients.details.credentials] client_id = "Client ID" client_secret = "Client Secret" -title = "Title" +title = "Client Credentials" [ui.dev.clients.details.endpoints] read_only = "Read Only" -title = "Title" +title = "OIDC Endpoints" [ui.dev.clients.details.redirect] callback_label = "Callback Label" label = "Redirect URIs" placeholder = "https://your-app.com/callback, http://localhost:3000/auth/callback" save = "Save" -title = "Title" +title = "Redirection Settings" [ui.dev.clients.details.secret] hide = "Hide" @@ -1015,7 +1022,7 @@ rotate = "Rotate" show = "Show" [ui.dev.clients.details.security] -title = "Title" +title = "Security Note" [ui.dev.clients.details.tab] connection = "Federation" @@ -1144,6 +1151,7 @@ unknown = "Unknown" expired = "Session expired" expiring = "Expiring soon: {{minutes}}m {{seconds}}s left" remaining = "Expires in: {{minutes}}m {{seconds}}s" +refresh = "Refresh session expiry" [ui.userfront] app_title = "Baron SW Portal" diff --git a/devfront/src/locales/ko.toml b/devfront/src/locales/ko.toml index d832d1e4..69bc9dae 100644 --- a/devfront/src/locales/ko.toml +++ b/devfront/src/locales/ko.toml @@ -926,10 +926,10 @@ admin = "Admin" user = "User" [ui.common.status] -active = "Active" -blocked = "Blocked" +active = "활성" +blocked = "차단됨" failure = "실패" -inactive = "Inactive" +inactive = "비활성" ok = "정상" pending = "준비 중" success = "성공" @@ -979,6 +979,13 @@ active_grants = "활성 권한" avg_scopes = "사용자당 평균 권한 수" total_scopes = "전체 부여된 권한 수" +[ui.dev.clients.stats] +total = "총 애플리케이션" +active_sessions = "활성 세션" +auth_failures = "인증 실패 (24h)" +realtime = "실시간" +stable = "안정" + [ui.dev.clients.consents.table] action = "작업" first_granted = "최초 동의" @@ -1020,14 +1027,14 @@ title = "보안 메모" [ui.dev.clients.details.tab] connection = "연동 설정" -consents = "Consent & Users" -settings = "Settings" +consents = "동의 및 사용자" +settings = "설정" [ui.dev.clients.general] create = "앱 생성" display_new = "연동 앱 추가" -title_create = "Create Client" -title_edit = "Client Settings" +title_create = "연동 앱 생성" +title_edit = "연동 앱 설정" [ui.dev.clients.federation] title = "Identity Federation" @@ -1145,6 +1152,7 @@ unknown = "확인 불가" expired = "세션 만료" expiring = "만료 임박: {{minutes}}분 {{seconds}}초 남음" remaining = "만료 예정: {{minutes}}분 {{seconds}}초 남음" +refresh = "세션 만료 시간 갱신" [ui.userfront] app_title = "Baron SW 포탈" diff --git a/devfront/src/locales/template.toml b/devfront/src/locales/template.toml index b1cb4d35..ed9939a1 100644 --- a/devfront/src/locales/template.toml +++ b/devfront/src/locales/template.toml @@ -990,6 +990,13 @@ active_grants = "" avg_scopes = "" total_scopes = "" +[ui.dev.clients.stats] +total = "" +active_sessions = "" +auth_failures = "" +realtime = "" +stable = "" + [ui.dev.clients.consents.table] action = "" first_granted = "" @@ -1156,6 +1163,7 @@ unknown = "" expired = "" expiring = "" remaining = "" +refresh = "" [ui.userfront] app_title = "" diff --git a/locales/en.toml b/locales/en.toml index 3ee69959..ce690bf7 100644 --- a/locales/en.toml +++ b/locales/en.toml @@ -361,8 +361,8 @@ dev_scope = "Dev Scope" hydra_health = "Hydra Health" [msg.dev.sidebar] -notice = "Notice" -notice_detail = "Notice Detail" +notice = "Developer Console" +notice_detail = "Register and manage client applications." [msg.info] saved_success = "Saved successfully." @@ -1152,6 +1152,13 @@ active_grants = "Active Grants" avg_scopes = "Avg. Scopes per User" total_scopes = "Total Scopes Issued" +[ui.dev.clients.stats] +total = "Total Applications" +active_sessions = "Active Sessions" +auth_failures = "Auth Failures (24h)" +realtime = "Realtime" +stable = "Stable" + [ui.dev.clients.consents.table] action = "Action" first_granted = "First Granted" @@ -1164,24 +1171,24 @@ user = "User" [ui.dev.clients.details] [ui.dev.clients.details.breadcrumb] -current = "Current" -section = "Applications" +current = "App Details" +section = "Connected Applications" [ui.dev.clients.details.credentials] client_id = "Client ID" client_secret = "Client Secret" -title = "Title" +title = "Client Credentials" [ui.dev.clients.details.endpoints] read_only = "Read Only" -title = "Title" +title = "OIDC Endpoints" [ui.dev.clients.details.redirect] callback_label = "Callback Label" label = "Redirect URIs" placeholder = "https://your-app.com/callback, http://localhost:3000/auth/callback" save = "Save" -title = "Title" +title = "Redirection Settings" [ui.dev.clients.details.secret] hide = "Hide" @@ -1189,7 +1196,7 @@ rotate = "Rotate" show = "Show" [ui.dev.clients.details.security] -title = "Title" +title = "Security Note" [ui.dev.clients.details.tab] connection = "Federation" diff --git a/locales/ko.toml b/locales/ko.toml index 76c20154..5bb3325a 100644 --- a/locales/ko.toml +++ b/locales/ko.toml @@ -1080,10 +1080,10 @@ admin = "Admin" user = "User" [ui.common.status] -active = "Active" -blocked = "Blocked" +active = "활성" +blocked = "차단됨" failure = "실패" -inactive = "Inactive" +inactive = "비활성" ok = "정상" pending = "준비 중" success = "성공" @@ -1152,6 +1152,13 @@ active_grants = "Active Grants" avg_scopes = "Avg. Scopes per User" total_scopes = "Total Scopes Issued" +[ui.dev.clients.stats] +total = "총 애플리케이션" +active_sessions = "활성 세션" +auth_failures = "인증 실패 (24h)" +realtime = "실시간" +stable = "안정" + [ui.dev.clients.consents.table] action = "Action" first_granted = "First Granted" @@ -1193,14 +1200,14 @@ title = "보안 메모" [ui.dev.clients.details.tab] connection = "연동 설정" -consents = "Consent & Users" -settings = "Settings" +consents = "동의 및 사용자" +settings = "설정" [ui.dev.clients.general] create = "앱 생성" display_new = "연동 앱 추가" -title_create = "Create Client" -title_edit = "Client Settings" +title_create = "연동 앱 생성" +title_edit = "연동 앱 설정" [ui.dev.clients.federation] title = "Identity Federation" diff --git a/locales/template.toml b/locales/template.toml index 0481ac57..65961d15 100644 --- a/locales/template.toml +++ b/locales/template.toml @@ -1034,6 +1034,13 @@ active_grants = "" avg_scopes = "" total_scopes = "" +[ui.dev.clients.stats] +total = "" +active_sessions = "" +auth_failures = "" +realtime = "" +stable = "" + [ui.dev.clients.consents.table] action = "" first_granted = "" diff --git a/userfront-e2e/tests/oidc-login-challenge.spec.ts b/userfront-e2e/tests/oidc-login-challenge.spec.ts new file mode 100644 index 00000000..920a69b4 --- /dev/null +++ b/userfront-e2e/tests/oidc-login-challenge.spec.ts @@ -0,0 +1,81 @@ +import { expect, test, type Page, type Route } from '@playwright/test'; + +async function mockUserfrontApisForRepro( + page: Page, + options: { sessionStatus: number } = { sessionStatus: 401 }, +): Promise { + await page.route('**/api/v1/**', async (route: Route) => { + const requestUrl = new URL(route.request().url()); + const path = requestUrl.pathname; + + if (path.endsWith('/api/v1/user/me')) { + await route.fulfill({ + status: options.sessionStatus, + contentType: 'application/json', + body: JSON.stringify({ error: 'unauthorized' }), + }); + return; + } + + if (path.endsWith('/api/v1/client-log')) { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ ok: true }), + }); + return; + } + + // Default mock for other APIs + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({}), + }); + }); +} + +test.describe('Issue #345 Reproduction (Log-based Validation)', () => { + test('비로그인 상태에서 login_challenge와 함께 signin 진입 시 루프 없이 로그가 정상 출력되어야 한다', async ({ page }) => { + const logs: string[] = []; + page.on('console', msg => { + const text = msg.text(); + logs.push(text); + console.log(`[Browser] ${text}`); + }); + + const requests: string[] = []; + page.on('request', request => { + if (request.isNavigationRequest()) { + requests.push(request.url()); + } + }); + + await mockUserfrontApisForRepro(page, { sessionStatus: 401 }); + + const targetUrl = '/ko/signin?login_challenge=repro_challenge_12345'; + await page.goto(targetUrl); + + // WASM 앱 로딩 및 로직 실행 대기 + await page.waitForTimeout(7000); + + const currentUrl = page.url(); + const signinNavigations = requests.filter(url => url.includes('/signin')); + + // [검증 1] URL 유지 확인 + expect(currentUrl).toContain('login_challenge=repro_challenge_12345'); + + // [검증 2] 리다이렉트 루프 발생 여부 확인 (최초 진입 1회만 있어야 함) + expect(signinNavigations.length).toBeLessThanOrEqual(1); + + // [검증 3] 핵심 로직 로그 확인 (성공의 결정적 증거) + // 이전에는 여기서 Exception이 발생했으나, 이제는 아래 로그가 찍혀야 함 + const hasSuccessLog = logs.some(log => + log.includes('[Auth] OIDC auto-accept: No active session (status: 401)') + ); + + expect(hasSuccessLog).toBe(true); + + console.log('✅ 루프가 해결되었으며, 로그 검증을 통해 정상 동작을 확인했습니다.'); + }); +}); diff --git a/userfront/assets/translations/ko.toml b/userfront/assets/translations/ko.toml index c655ad51..7c77d37e 100644 --- a/userfront/assets/translations/ko.toml +++ b/userfront/assets/translations/ko.toml @@ -349,10 +349,10 @@ admin = "Admin" user = "User" [ui.common.status] -active = "Active" -blocked = "Blocked" +active = "활성" +blocked = "차단됨" failure = "실패" -inactive = "Inactive" +inactive = "비활성" ok = "정상" pending = "준비 중" success = "성공" diff --git a/userfront/lib/features/auth/presentation/login_screen.dart b/userfront/lib/features/auth/presentation/login_screen.dart index 43f51370..e1af67f8 100644 --- a/userfront/lib/features/auth/presentation/login_screen.dart +++ b/userfront/lib/features/auth/presentation/login_screen.dart @@ -161,7 +161,14 @@ class _LoginScreenState extends ConsumerState final provider = pendingProvider ?? AuthTokenStore.getProvider() ?? 'ory'; try { - await AuthProxyService.checkCookieSession(); + final status = await AuthProxyService.getSessionStatus(useCookie: true); + if (status != 200) { + debugPrint( + "[Auth] Cookie session check: No active session (status: $status)", + ); + return; + } + if (!shouldPromoteCookieSession( currentToken: AuthTokenStore.getToken(), loginChallenge: loginChallenge, @@ -242,11 +249,18 @@ class _LoginScreenState extends ConsumerState } try { - await AuthProxyService.checkCookieSession(); - AuthTokenStore.setCookieMode( - provider: AuthTokenStore.getProvider() ?? 'ory', - ); - await _acceptOidcLoginAndRedirect(); + // 401 응답은 세션이 없는 정상적인 상태이므로 예외로 처리하지 않고 우아하게 중단합니다. + final status = await AuthProxyService.getSessionStatus(useCookie: true); + if (status == 200) { + AuthTokenStore.setCookieMode( + provider: AuthTokenStore.getProvider() ?? 'ory', + ); + await _acceptOidcLoginAndRedirect(); + } else { + debugPrint( + "[Auth] OIDC auto-accept: No active session (status: $status)", + ); + } } catch (e) { debugPrint("[Auth] OIDC auto-accept cookie check failed: $e"); } diff --git a/userfront/pubspec.lock b/userfront/pubspec.lock index ae003ec3..fecd33f1 100644 --- a/userfront/pubspec.lock +++ b/userfront/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: characters - sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.0" cli_config: dependency: transitive description: @@ -268,6 +268,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + js: + dependency: transitive + description: + name: js + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" leak_tracker: dependency: transitive description: @@ -320,18 +328,18 @@ packages: dependency: transitive description: name: matcher - sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.18" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.13.0" + version: "0.11.1" meta: dependency: transitive description: @@ -645,26 +653,26 @@ packages: dependency: transitive description: name: test - sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a" + sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7" url: "https://pub.dev" source: hosted - version: "1.29.0" + version: "1.26.3" test_api: dependency: transitive description: name: test_api - sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.dev" source: hosted - version: "0.7.9" + version: "0.7.7" test_core: dependency: transitive description: name: test_core - sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943" + sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0" url: "https://pub.dev" source: hosted - version: "0.6.15" + version: "0.6.12" toml: dependency: "direct main" description: