this repo has no description

Misc fixes

lewis dd67947e 79e64a8c

+3 -2
frontend/src/lib/api.ts
··· 57 message: res.statusText, 58 })); 59 if ( 60 - res.status === 401 && err.error === "AuthenticationFailed" && token && 61 - tokenRefreshCallback && !skipRetry 62 ) { 63 const newToken = await tokenRefreshCallback(); 64 if (newToken && newToken !== token) {
··· 57 message: res.statusText, 58 })); 59 if ( 60 + res.status === 401 && 61 + (err.error === "AuthenticationFailed" || err.error === "ExpiredToken") && 62 + token && tokenRefreshCallback && !skipRetry 63 ) { 64 const newToken = await tokenRefreshCallback(); 65 if (newToken && newToken !== token) {
+2
frontend/src/locales/en.json
··· 172 "navCommsDesc": "Discord, Telegram, Signal channels", 173 "navRepo": "Repository Explorer", 174 "navRepoDesc": "Browse and manage raw AT Protocol records", 175 "navAdmin": "Admin Panel", 176 "navAdminDesc": "Server stats and admin operations" 177 },
··· 172 "navCommsDesc": "Discord, Telegram, Signal channels", 173 "navRepo": "Repository Explorer", 174 "navRepoDesc": "Browse and manage raw AT Protocol records", 175 + "navDelegation": "Delegation", 176 + "navDelegationDesc": "Manage account controllers and delegated accounts", 177 "navAdmin": "Admin Panel", 178 "navAdminDesc": "Server stats and admin operations" 179 },
+2
frontend/src/locales/fi.json
··· 172 "navCommsDesc": "Discord-, Telegram-, Signal-kanavat", 173 "navRepo": "Tietovarastoselaaja", 174 "navRepoDesc": "Selaa ja hallitse raakoja AT Protocol -tietueita", 175 "navAdmin": "Ylläpitopaneeli", 176 "navAdminDesc": "Palvelintilastot ja ylläpitotoiminnot" 177 },
··· 172 "navCommsDesc": "Discord-, Telegram-, Signal-kanavat", 173 "navRepo": "Tietovarastoselaaja", 174 "navRepoDesc": "Selaa ja hallitse raakoja AT Protocol -tietueita", 175 + "navDelegation": "Delegointi", 176 + "navDelegationDesc": "Hallitse tilin ohjaajia ja delegoituja tilejä", 177 "navAdmin": "Ylläpitopaneeli", 178 "navAdminDesc": "Palvelintilastot ja ylläpitotoiminnot" 179 },
+2
frontend/src/locales/ja.json
··· 172 "navCommsDesc": "Discord、Telegram、Signal チャンネル", 173 "navRepo": "リポジトリエクスプローラー", 174 "navRepoDesc": "AT Protocol レコードを閲覧・管理", 175 "navAdmin": "管理パネル", 176 "navAdminDesc": "サーバー統計と管理操作" 177 },
··· 172 "navCommsDesc": "Discord、Telegram、Signal チャンネル", 173 "navRepo": "リポジトリエクスプローラー", 174 "navRepoDesc": "AT Protocol レコードを閲覧・管理", 175 + "navDelegation": "委任", 176 + "navDelegationDesc": "アカウントコントローラーと委任アカウントを管理", 177 "navAdmin": "管理パネル", 178 "navAdminDesc": "サーバー統計と管理操作" 179 },
+2
frontend/src/locales/ko.json
··· 172 "navCommsDesc": "Discord, Telegram, Signal 채널", 173 "navRepo": "저장소 탐색기", 174 "navRepoDesc": "AT Protocol 레코드 탐색 및 관리", 175 "navAdmin": "관리 패널", 176 "navAdminDesc": "서버 통계 및 관리 작업" 177 },
··· 172 "navCommsDesc": "Discord, Telegram, Signal 채널", 173 "navRepo": "저장소 탐색기", 174 "navRepoDesc": "AT Protocol 레코드 탐색 및 관리", 175 + "navDelegation": "위임", 176 + "navDelegationDesc": "계정 컨트롤러 및 위임된 계정 관리", 177 "navAdmin": "관리 패널", 178 "navAdminDesc": "서버 통계 및 관리 작업" 179 },
+2
frontend/src/locales/sv.json
··· 172 "navCommsDesc": "Discord, Telegram, Signal-kanaler", 173 "navRepo": "Dataförvarsutforskare", 174 "navRepoDesc": "Bläddra och hantera råa AT Protocol-poster", 175 "navAdmin": "Adminpanel", 176 "navAdminDesc": "Serverstatistik och administratörsoperationer" 177 },
··· 172 "navCommsDesc": "Discord, Telegram, Signal-kanaler", 173 "navRepo": "Dataförvarsutforskare", 174 "navRepoDesc": "Bläddra och hantera råa AT Protocol-poster", 175 + "navDelegation": "Delegering", 176 + "navDelegationDesc": "Hantera kontokontrollanter och delegerade konton", 177 "navAdmin": "Adminpanel", 178 "navAdminDesc": "Serverstatistik och administratörsoperationer" 179 },
+3
frontend/src/locales/zh.json
··· 172 "navCommsDesc": "Discord、Telegram、Signal 渠道设置", 173 "navRepo": "数据浏览器", 174 "navRepoDesc": "浏览和管理原始 AT Protocol 记录", 175 "navAdmin": "管理后台", 176 "navAdminDesc": "服务器统计和管理操作" 177 }, ··· 912 "actor": "执行者", 913 "controller": "控制者", 914 "account": "账户", 915 "details": "详情", 916 "actionGrantCreated": "授权创建", 917 "actionGrantRevoked": "授权撤销",
··· 172 "navCommsDesc": "Discord、Telegram、Signal 渠道设置", 173 "navRepo": "数据浏览器", 174 "navRepoDesc": "浏览和管理原始 AT Protocol 记录", 175 + "navDelegation": "账户委托", 176 + "navDelegationDesc": "管理控制者和委托账户", 177 "navAdmin": "管理后台", 178 "navAdminDesc": "服务器统计和管理操作" 179 }, ··· 914 "actor": "执行者", 915 "controller": "控制者", 916 "account": "账户", 917 + "accountCreated": "已创建委托账户:{handle}", 918 "details": "详情", 919 "actionGrantCreated": "授权创建", 920 "actionGrantRevoked": "授权撤销",
+2 -2
frontend/src/routes/Dashboard.svelte
··· 187 <p>{$_('dashboard.navRepoDesc')}</p> 188 </a> 189 <a href="#/controllers" class="nav-card"> 190 - <h3>Delegation</h3> 191 - <p>Manage account controllers and delegated accounts</p> 192 </a> 193 {#if auth.session.isAdmin} 194 <a href="#/admin" class="nav-card admin-card">
··· 187 <p>{$_('dashboard.navRepoDesc')}</p> 188 </a> 189 <a href="#/controllers" class="nav-card"> 190 + <h3>{$_('dashboard.navDelegation')}</h3> 191 + <p>{$_('dashboard.navDelegationDesc')}</p> 192 </a> 193 {#if auth.session.isAdmin} 194 <a href="#/admin" class="nav-card admin-card">
+1 -1
src/api/server/verify_email.rs
··· 28 identifier: input.email, 29 }; 30 31 - let result = super::verify_token::verify_token_internal(&state, None, token_input).await?; 32 33 Ok(Json(VerifyMigrationEmailOutput { 34 success: result.success,
··· 28 identifier: input.email, 29 }; 30 31 + let result = super::verify_token::verify_token_internal(&state, token_input).await?; 32 33 Ok(Json(VerifyMigrationEmailOutput { 34 success: result.success,
+2 -46
src/api/server/verify_token.rs
··· 1 use axum::{ 2 Json, 3 extract::State, 4 - http::{HeaderMap, StatusCode}, 5 }; 6 use serde::{Deserialize, Serialize}; 7 use serde_json::json; ··· 30 31 pub async fn verify_token( 32 State(state): State<AppState>, 33 - headers: HeaderMap, 34 Json(input): Json<VerifyTokenInput>, 35 ) -> Result<Json<VerifyTokenOutput>, (StatusCode, Json<serde_json::Value>)> { 36 - verify_token_internal(&state, Some(&headers), input).await 37 } 38 39 pub async fn verify_token_internal( 40 state: &AppState, 41 - headers: Option<&HeaderMap>, 42 input: VerifyTokenInput, 43 ) -> Result<Json<VerifyTokenOutput>, (StatusCode, Json<serde_json::Value>)> { 44 let normalized_token = normalize_token_input(&input.token); ··· 95 .await 96 } 97 VerificationPurpose::ChannelUpdate => { 98 - let auth_did = extract_and_validate_auth(state, headers).await?; 99 - if auth_did != token_data.did { 100 - return Err(( 101 - StatusCode::BAD_REQUEST, 102 - Json( 103 - json!({ "error": "InvalidToken", "message": "Token does not match authenticated account" }), 104 - ), 105 - )); 106 - } 107 handle_channel_update(state, &token_data.did, &token_data.channel, &identifier).await 108 } 109 VerificationPurpose::Signup => { ··· 111 .await 112 } 113 } 114 - } 115 - 116 - async fn extract_and_validate_auth( 117 - state: &AppState, 118 - headers: Option<&HeaderMap>, 119 - ) -> Result<String, (StatusCode, Json<serde_json::Value>)> { 120 - let headers = headers.ok_or_else(|| { 121 - ( 122 - StatusCode::UNAUTHORIZED, 123 - Json(json!({ "error": "AuthenticationRequired", "message": "Authentication required for this verification" })), 124 - ) 125 - })?; 126 - 127 - let token = crate::auth::extract_bearer_token_from_header( 128 - headers.get("Authorization").and_then(|h| h.to_str().ok()), 129 - ) 130 - .ok_or_else(|| { 131 - ( 132 - StatusCode::UNAUTHORIZED, 133 - Json(json!({ "error": "AuthenticationRequired", "message": "Authentication required for this verification" })), 134 - ) 135 - })?; 136 - 137 - let user = crate::auth::validate_bearer_token(&state.db, &token) 138 - .await 139 - .map_err(|_| { 140 - ( 141 - StatusCode::UNAUTHORIZED, 142 - Json(json!({ "error": "AuthenticationFailed", "message": "Invalid authentication token" })), 143 - ) 144 - })?; 145 - 146 - Ok(user.did) 147 } 148 149 async fn handle_migration_verification(
··· 1 use axum::{ 2 Json, 3 extract::State, 4 + http::StatusCode, 5 }; 6 use serde::{Deserialize, Serialize}; 7 use serde_json::json; ··· 30 31 pub async fn verify_token( 32 State(state): State<AppState>, 33 Json(input): Json<VerifyTokenInput>, 34 ) -> Result<Json<VerifyTokenOutput>, (StatusCode, Json<serde_json::Value>)> { 35 + verify_token_internal(&state, input).await 36 } 37 38 pub async fn verify_token_internal( 39 state: &AppState, 40 input: VerifyTokenInput, 41 ) -> Result<Json<VerifyTokenOutput>, (StatusCode, Json<serde_json::Value>)> { 42 let normalized_token = normalize_token_input(&input.token); ··· 93 .await 94 } 95 VerificationPurpose::ChannelUpdate => { 96 handle_channel_update(state, &token_data.did, &token_data.channel, &identifier).await 97 } 98 VerificationPurpose::Signup => { ··· 100 .await 101 } 102 } 103 } 104 105 async fn handle_migration_verification(
+1 -3
src/api/verification.rs
··· 2 use axum::{ 3 Json, 4 extract::State, 5 - http::HeaderMap, 6 response::{IntoResponse, Response}, 7 }; 8 use serde::Deserialize; ··· 18 19 pub async fn confirm_channel_verification( 20 State(state): State<AppState>, 21 - headers: HeaderMap, 22 Json(input): Json<ConfirmChannelVerificationInput>, 23 ) -> Response { 24 let token_input = crate::api::server::VerifyTokenInput { ··· 26 identifier: input.identifier, 27 }; 28 29 - match crate::api::server::verify_token_internal(&state, Some(&headers), token_input).await { 30 Ok(output) => Json(json!({"success": output.success})).into_response(), 31 Err((status, err_json)) => (status, err_json).into_response(), 32 }
··· 2 use axum::{ 3 Json, 4 extract::State, 5 response::{IntoResponse, Response}, 6 }; 7 use serde::Deserialize; ··· 17 18 pub async fn confirm_channel_verification( 19 State(state): State<AppState>, 20 Json(input): Json<ConfirmChannelVerificationInput>, 21 ) -> Response { 22 let token_input = crate::api::server::VerifyTokenInput { ··· 24 identifier: input.identifier, 25 }; 26 27 + match crate::api::server::verify_token_internal(&state, token_input).await { 28 Ok(output) => Json(json!({"success": output.success})).into_response(), 29 Err((status, err_json)) => (status, err_json).into_response(), 30 }
+18 -18
src/comms/locale.rs
··· 49 password_reset_subject: "Password Reset - {hostname}", 50 password_reset_body: "Hello @{handle},\n\nYour password reset code is: {code}\n\nThis code will expire in 10 minutes.\n\nIf you did not request this, please ignore this message.", 51 email_update_subject: "Confirm your new email - {hostname}", 52 - email_update_body: "Hello @{handle},\n\nYour verification code is:\n{code}\n\nCopy the code above and enter it at:\n{verify_page}\n\nThis code will expire in 10 minutes.\n\nIf you did not request this, please ignore this email.\n\n(Or if you like to live dangerously: {verify_link})", 53 account_deletion_subject: "Account Deletion Request - {hostname}", 54 account_deletion_body: "Hello @{handle},\n\nYour account deletion confirmation code is: {code}\n\nThis code will expire in 10 minutes.\n\nIf you did not request this, please secure your account immediately.", 55 plc_operation_subject: "{hostname} - PLC Operation Token", ··· 59 passkey_recovery_subject: "Account Recovery - {hostname}", 60 passkey_recovery_body: "Hello @{handle},\n\nYou requested to recover your passkey-only account.\n\nClick the link below to set a temporary password and regain access:\n{url}\n\nThis link will expire in 1 hour.\n\nIf you did not request this, please ignore this message. Your account remains secure.", 61 signup_verification_subject: "Verify your account - {hostname}", 62 - signup_verification_body: "Welcome! Your verification code is:\n{code}\n\nCopy the code above and enter it at:\n{verify_page}\n\nThis code will expire in 30 minutes.\n\nIf you did not create an account on {hostname}, please ignore this message.\n\n(Or if you like to live dangerously: {verify_link})", 63 legacy_login_subject: "Security Alert: Legacy Login Detected - {hostname}", 64 legacy_login_body: "Hello @{handle},\n\nA login to your account was detected using a legacy app (like Bluesky) that doesn't support TOTP verification.\n\nDetails:\n- Time: {timestamp}\n- IP Address: {ip}\n\nYour TOTP protection was bypassed for this login. The session has limited permissions for sensitive operations.\n\nIf this wasn't you, please:\n1. Change your password immediately\n2. Review your active sessions\n3. Consider disabling legacy app logins in your security settings\n\nStay safe,\n{hostname}", 65 migration_verification_subject: "Verify your email - {hostname}", 66 - migration_verification_body: "Welcome to {hostname}!\n\nYour account has been migrated successfully. To complete the setup, please verify your email address.\n\nYour verification code is:\n{code}\n\nCopy the code above and enter it at:\n{verify_page}\n\nThis code will expire in 48 hours.\n\nIf you did not migrate your account, please ignore this email.\n\n(Or if you like to live dangerously: {verify_link})", 67 }; 68 69 static STRINGS_ZH: NotificationStrings = NotificationStrings { ··· 72 password_reset_subject: "密码重置 - {hostname}", 73 password_reset_body: "您好 @{handle},\n\n您的密码重置验证码是:{code}\n\n此验证码将在10分钟后过期。\n\n如果这不是您的操作,请忽略此消息。", 74 email_update_subject: "确认您的新邮箱 - {hostname}", 75 - email_update_body: "您好 @{handle},\n\n您的验证码是:\n{code}\n\n复制上述验证码并在此输入:\n{verify_page}\n\n此验证码将在10分钟后过期。\n\n如果这不是您的操作,请忽略此邮件。\n\n(或者直接点击链接:{verify_link})", 76 account_deletion_subject: "账户删除请求 - {hostname}", 77 account_deletion_body: "您好 @{handle},\n\n您的账户删除确认码是:{code}\n\n此验证码将在10分钟后过期。\n\n如果这不是您的操作,请立即保护您的账户。", 78 plc_operation_subject: "{hostname} - PLC 操作令牌", ··· 82 passkey_recovery_subject: "账户恢复 - {hostname}", 83 passkey_recovery_body: "您好 @{handle},\n\n您请求恢复仅通行密钥账户的访问权限。\n\n点击以下链接设置临时密码并恢复访问:\n{url}\n\n此链接将在1小时后过期。\n\n如果这不是您的操作,请忽略此消息。您的账户仍然安全。", 84 signup_verification_subject: "验证您的账户 - {hostname}", 85 - signup_verification_body: "欢迎!您的验证码是:\n{code}\n\n复制上述验证码并在此输入:\n{verify_page}\n\n此验证码将在30分钟后过期。\n\n如果您没有在 {hostname} 上创建账户,请忽略此消息。\n\n(或者直接点击链接:{verify_link})", 86 legacy_login_subject: "安全提醒:检测到传统应用登录 - {hostname}", 87 legacy_login_body: "您好 @{handle},\n\n检测到使用不支持 TOTP 验证的传统应用(如 Bluesky)登录您的账户。\n\n详细信息:\n- 时间:{timestamp}\n- IP 地址:{ip}\n\n此次登录绕过了 TOTP 保护。该会话对敏感操作的权限有限。\n\n如果这不是您的操作,请:\n1. 立即更改密码\n2. 检查您的活跃会话\n3. 考虑在安全设置中禁用传统应用登录\n\n请注意安全,\n{hostname}", 88 migration_verification_subject: "验证您的邮箱 - {hostname}", 89 - migration_verification_body: "欢迎来到 {hostname}!\n\n您的账户已成功迁移。要完成设置,请验证您的邮箱地址。\n\n您的验证码是:\n{code}\n\n复制上述验证码并在此输入:\n{verify_page}\n\n此验证码将在 48 小时后过期。\n\n如果您没有迁移账户,请忽略此邮件。\n\n(或者直接点击链接:{verify_link})", 90 }; 91 92 static STRINGS_JA: NotificationStrings = NotificationStrings { ··· 95 password_reset_subject: "パスワードリセット - {hostname}", 96 password_reset_body: "@{handle} 様\n\nパスワードリセットコードは:{code}\n\nこのコードは10分後に期限切れとなります。\n\nこの操作に心当たりがない場合は、このメッセージを無視してください。", 97 email_update_subject: "新しいメールアドレスの確認 - {hostname}", 98 - email_update_body: "@{handle} 様\n\n確認コードは:\n{code}\n\n上記のコードをコピーして、こちらで入力してください:\n{verify_page}\n\nこのコードは10分後に期限切れとなります。\n\nこの操作に心当たりがない場合は、このメールを無視してください。\n\n(自己責任でワンクリック認証:{verify_link})", 99 account_deletion_subject: "アカウント削除リクエスト - {hostname}", 100 account_deletion_body: "@{handle} 様\n\nアカウント削除の確認コードは:{code}\n\nこのコードは10分後に期限切れとなります。\n\nこの操作に心当たりがない場合は、直ちにアカウントを保護してください。", 101 plc_operation_subject: "{hostname} - PLC 操作トークン", ··· 105 passkey_recovery_subject: "アカウント復旧 - {hostname}", 106 passkey_recovery_body: "@{handle} 様\n\nパスキー専用アカウントの復旧をリクエストされました。\n\n以下のリンクをクリックして一時パスワードを設定し、アクセスを回復してください:\n{url}\n\nこのリンクは1時間後に期限切れとなります。\n\nこの操作に心当たりがない場合は、このメッセージを無視してください。アカウントは安全なままです。", 107 signup_verification_subject: "アカウント認証 - {hostname}", 108 - signup_verification_body: "ようこそ!認証コードは:\n{code}\n\n上記のコードをコピーして、こちらで入力してください:\n{verify_page}\n\nこのコードは30分後に期限切れとなります。\n\n{hostname} でアカウントを作成していない場合は、このメールを無視してください。\n\n(自己責任でワンクリック認証:{verify_link})", 109 legacy_login_subject: "セキュリティ警告:レガシーログインを検出 - {hostname}", 110 legacy_login_body: "@{handle} 様\n\nTOTP 認証に対応していないレガシーアプリ(Bluesky など)からのログインが検出されました。\n\n詳細:\n- 時刻:{timestamp}\n- IP アドレス:{ip}\n\nこのログインでは TOTP 保護がバイパスされました。このセッションは機密操作に対する権限が制限されています。\n\n心当たりがない場合は:\n1. 直ちにパスワードを変更してください\n2. アクティブなセッションを確認してください\n3. セキュリティ設定でレガシーアプリのログインを無効にすることを検討してください\n\nご注意ください。\n{hostname}", 111 migration_verification_subject: "メールアドレスの認証 - {hostname}", 112 - migration_verification_body: "{hostname} へようこそ!\n\nアカウントの移行が完了しました。設定を完了するには、メールアドレスを認証してください。\n\n認証コードは:\n{code}\n\n上記のコードをコピーして、こちらで入力してください:\n{verify_page}\n\nこのコードは48時間後に期限切れとなります。\n\nアカウントを移行していない場合は、このメールを無視してください。\n\n(自己責任でワンクリック認証:{verify_link})", 113 }; 114 115 static STRINGS_KO: NotificationStrings = NotificationStrings { ··· 118 password_reset_subject: "비밀번호 재설정 - {hostname}", 119 password_reset_body: "안녕하세요 @{handle}님,\n\n비밀번호 재설정 코드는: {code}\n\n이 코드는 10분 후에 만료됩니다.\n\n요청하지 않으셨다면 이 메시지를 무시하세요.", 120 email_update_subject: "새 이메일 주소 확인 - {hostname}", 121 - email_update_body: "안녕하세요 @{handle}님,\n\n인증 코드는:\n{code}\n\n위 코드를 복사하여 여기에 입력하세요:\n{verify_page}\n\n이 코드는 10분 후에 만료됩니다.\n\n요청하지 않으셨다면 이 이메일을 무시하세요.\n\n(위험을 감수하고 원클릭 인증: {verify_link})", 122 account_deletion_subject: "계정 삭제 요청 - {hostname}", 123 account_deletion_body: "안녕하세요 @{handle}님,\n\n계정 삭제 확인 코드는: {code}\n\n이 코드는 10분 후에 만료됩니다.\n\n요청하지 않으셨다면 즉시 계정을 보호하세요.", 124 plc_operation_subject: "{hostname} - PLC 작업 토큰", ··· 128 passkey_recovery_subject: "계정 복구 - {hostname}", 129 passkey_recovery_body: "안녕하세요 @{handle}님,\n\n패스키 전용 계정 복구를 요청하셨습니다.\n\n아래 링크를 클릭하여 임시 비밀번호를 설정하고 액세스를 복구하세요:\n{url}\n\n이 링크는 1시간 후에 만료됩니다.\n\n요청하지 않으셨다면 이 메시지를 무시하세요. 계정은 안전하게 유지됩니다.", 130 signup_verification_subject: "계정 인증 - {hostname}", 131 - signup_verification_body: "환영합니다! 인증 코드는:\n{code}\n\n위 코드를 복사하여 여기에 입력하세요:\n{verify_page}\n\n이 코드는 30분 후에 만료됩니다.\n\n{hostname}에서 계정을 만들지 않았다면 이 이메일을 무시하세요.\n\n(위험을 감수하고 원클릭 인증: {verify_link})", 132 legacy_login_subject: "보안 알림: 레거시 로그인 감지 - {hostname}", 133 legacy_login_body: "안녕하세요 @{handle}님,\n\nTOTP 인증을 지원하지 않는 레거시 앱(예: Bluesky)을 사용한 로그인이 감지되었습니다.\n\n세부 정보:\n- 시간: {timestamp}\n- IP 주소: {ip}\n\n이 로그인에서 TOTP 보호가 우회되었습니다. 이 세션은 민감한 작업에 대한 권한이 제한됩니다.\n\n본인이 아닌 경우:\n1. 즉시 비밀번호를 변경하세요\n2. 활성 세션을 검토하세요\n3. 보안 설정에서 레거시 앱 로그인 비활성화를 고려하세요\n\n{hostname} 드림", 134 migration_verification_subject: "이메일 인증 - {hostname}", 135 - migration_verification_body: "{hostname}에 오신 것을 환영합니다!\n\n계정 마이그레이션이 완료되었습니다. 설정을 완료하려면 이메일 주소를 인증하세요.\n\n인증 코드는:\n{code}\n\n위 코드를 복사하여 여기에 입력하세요:\n{verify_page}\n\n이 코드는 48시간 후에 만료됩니다.\n\n계정을 마이그레이션하지 않았다면 이 이메일을 무시하세요.\n\n(위험을 감수하고 원클릭 인증: {verify_link})", 136 }; 137 138 static STRINGS_SV: NotificationStrings = NotificationStrings { ··· 141 password_reset_subject: "Lösenordsåterställning - {hostname}", 142 password_reset_body: "Hej @{handle},\n\nDin kod för lösenordsåterställning är: {code}\n\nDenna kod upphör om 10 minuter.\n\nOm du inte begärde detta kan du ignorera detta meddelande.", 143 email_update_subject: "Bekräfta din nya e-post - {hostname}", 144 - email_update_body: "Hej @{handle},\n\nDin verifieringskod är:\n{code}\n\nKopiera koden ovan och ange den på:\n{verify_page}\n\nDenna kod upphör om 10 minuter.\n\nOm du inte begärde detta kan du ignorera detta meddelande.\n\n(Eller om du gillar att leva farligt: {verify_link})", 145 account_deletion_subject: "Begäran om kontoradering - {hostname}", 146 account_deletion_body: "Hej @{handle},\n\nDin bekräftelsekod för kontoradering är: {code}\n\nDenna kod upphör om 10 minuter.\n\nOm du inte begärde detta, skydda ditt konto omedelbart.", 147 plc_operation_subject: "{hostname} - PLC-operationstoken", ··· 151 passkey_recovery_subject: "Kontoåterställning - {hostname}", 152 passkey_recovery_body: "Hej @{handle},\n\nDu begärde att återställa ditt endast nyckelkonto.\n\nKlicka på länken nedan för att ställa in ett tillfälligt lösenord och återfå åtkomst:\n{url}\n\nDenna länk upphör om 1 timme.\n\nOm du inte begärde detta kan du ignorera detta meddelande. Ditt konto förblir säkert.", 153 signup_verification_subject: "Verifiera ditt konto - {hostname}", 154 - signup_verification_body: "Välkommen! Din verifieringskod är:\n{code}\n\nKopiera koden ovan och ange den på:\n{verify_page}\n\nDenna kod upphör om 30 minuter.\n\nOm du inte skapade ett konto på {hostname}, ignorera detta meddelande.\n\n(Eller om du gillar att leva farligt: {verify_link})", 155 legacy_login_subject: "Säkerhetsvarning: Äldre inloggning upptäckt - {hostname}", 156 legacy_login_body: "Hej @{handle},\n\nEn inloggning till ditt konto upptäcktes med en äldre app (som Bluesky) som inte stöder TOTP-verifiering.\n\nDetaljer:\n- Tid: {timestamp}\n- IP-adress: {ip}\n\nDitt TOTP-skydd kringgicks för denna inloggning. Sessionen har begränsade behörigheter för känsliga operationer.\n\nOm detta inte var du:\n1. Ändra ditt lösenord omedelbart\n2. Granska dina aktiva sessioner\n3. Överväg att inaktivera äldre appinloggningar i dina säkerhetsinställningar\n\nVar försiktig,\n{hostname}", 157 migration_verification_subject: "Verifiera din e-post - {hostname}", 158 - migration_verification_body: "Välkommen till {hostname}!\n\nDitt konto har migrerats framgångsrikt. För att slutföra installationen, verifiera din e-postadress.\n\nDin verifieringskod är:\n{code}\n\nKopiera koden ovan och ange den på:\n{verify_page}\n\nDenna kod upphör om 48 timmar.\n\nOm du inte migrerade ditt konto kan du ignorera detta meddelande.\n\n(Eller om du gillar att leva farligt: {verify_link})", 159 }; 160 161 static STRINGS_FI: NotificationStrings = NotificationStrings { ··· 164 password_reset_subject: "Salasanan palautus - {hostname}", 165 password_reset_body: "Hei @{handle},\n\nSalasanan palautuskoodisi on: {code}\n\nTämä koodi vanhenee 10 minuutissa.\n\nJos et pyytänyt tätä, voit jättää tämän viestin huomiotta.", 166 email_update_subject: "Vahvista uusi sähköpostisi - {hostname}", 167 - email_update_body: "Hei @{handle},\n\nVahvistuskoodisi on:\n{code}\n\nKopioi koodi yllä ja syötä se osoitteessa:\n{verify_page}\n\nTämä koodi vanhenee 10 minuutissa.\n\nJos et pyytänyt tätä, voit jättää tämän viestin huomiotta.\n\n(Tai jos pidät vaarallisesta elämästä: {verify_link})", 168 account_deletion_subject: "Tilin poistopyyntö - {hostname}", 169 account_deletion_body: "Hei @{handle},\n\nTilin poiston vahvistuskoodisi on: {code}\n\nTämä koodi vanhenee 10 minuutissa.\n\nJos et pyytänyt tätä, suojaa tilisi välittömästi.", 170 plc_operation_subject: "{hostname} - PLC-toimintotunniste", ··· 174 passkey_recovery_subject: "Tilin palautus - {hostname}", 175 passkey_recovery_body: "Hei @{handle},\n\nPyysit palauttamaan vain pääsyavaintilisi.\n\nKlikkaa alla olevaa linkkiä asettaaksesi väliaikaisen salasanan ja saadaksesi pääsyn takaisin:\n{url}\n\nTämä linkki vanhenee tunnissa.\n\nJos et pyytänyt tätä, voit jättää tämän viestin huomiotta. Tilisi pysyy turvassa.", 176 signup_verification_subject: "Vahvista tilisi - {hostname}", 177 - signup_verification_body: "Tervetuloa! Vahvistuskoodisi on:\n{code}\n\nKopioi koodi yllä ja syötä se osoitteessa:\n{verify_page}\n\nTämä koodi vanhenee 30 minuutissa.\n\nJos et luonut tiliä palveluun {hostname}, jätä tämä viesti huomiotta.\n\n(Tai jos pidät vaarallisesta elämästä: {verify_link})", 178 legacy_login_subject: "Turvallisuushälytys: Vanha kirjautuminen havaittu - {hostname}", 179 legacy_login_body: "Hei @{handle},\n\nTilillesi havaittiin kirjautuminen vanhalla sovelluksella (kuten Bluesky), joka ei tue TOTP-vahvistusta.\n\nTiedot:\n- Aika: {timestamp}\n- IP-osoite: {ip}\n\nTOTP-suojauksesi ohitettiin tässä kirjautumisessa. Istunnolla on rajoitetut oikeudet arkaluontoisiin toimintoihin.\n\nJos tämä et ollut sinä:\n1. Vaihda salasanasi välittömästi\n2. Tarkista aktiiviset istuntosi\n3. Harkitse vanhojen sovellusten kirjautumisen poistamista käytöstä turvallisuusasetuksissa\n\nOle varovainen,\n{hostname}", 180 migration_verification_subject: "Vahvista sähköpostisi - {hostname}", 181 - migration_verification_body: "Tervetuloa palveluun {hostname}!\n\nTilisi on siirretty onnistuneesti. Viimeistele asennus vahvistamalla sähköpostiosoitteesi.\n\nVahvistuskoodisi on:\n{code}\n\nKopioi koodi yllä ja syötä se osoitteessa:\n{verify_page}\n\nTämä koodi vanhenee 48 tunnissa.\n\nJos et siirtänyt tiliäsi, voit jättää tämän viestin huomiotta.\n\n(Tai jos pidät vaarallisesta elämästä: {verify_link})", 182 }; 183 184 pub fn format_message(template: &str, vars: &[(&str, &str)]) -> String {
··· 49 password_reset_subject: "Password Reset - {hostname}", 50 password_reset_body: "Hello @{handle},\n\nYour password reset code is: {code}\n\nThis code will expire in 10 minutes.\n\nIf you did not request this, please ignore this message.", 51 email_update_subject: "Confirm your new email - {hostname}", 52 + email_update_body: "Hello @{handle},\n\nYour verification code is:\n{code}\n\nCopy the code above and enter it at:\n{verify_page}\n\nThis code will expire in 10 minutes.\n\nOr if you like to live dangerously:\n{verify_link}\n\nIf you did not request this, please ignore this email.", 53 account_deletion_subject: "Account Deletion Request - {hostname}", 54 account_deletion_body: "Hello @{handle},\n\nYour account deletion confirmation code is: {code}\n\nThis code will expire in 10 minutes.\n\nIf you did not request this, please secure your account immediately.", 55 plc_operation_subject: "{hostname} - PLC Operation Token", ··· 59 passkey_recovery_subject: "Account Recovery - {hostname}", 60 passkey_recovery_body: "Hello @{handle},\n\nYou requested to recover your passkey-only account.\n\nClick the link below to set a temporary password and regain access:\n{url}\n\nThis link will expire in 1 hour.\n\nIf you did not request this, please ignore this message. Your account remains secure.", 61 signup_verification_subject: "Verify your account - {hostname}", 62 + signup_verification_body: "Welcome! Your verification code is:\n{code}\n\nCopy the code above and enter it at:\n{verify_page}\n\nThis code will expire in 30 minutes.\n\nOr if you like to live dangerously:\n{verify_link}\n\nIf you did not create an account on {hostname}, please ignore this message.", 63 legacy_login_subject: "Security Alert: Legacy Login Detected - {hostname}", 64 legacy_login_body: "Hello @{handle},\n\nA login to your account was detected using a legacy app (like Bluesky) that doesn't support TOTP verification.\n\nDetails:\n- Time: {timestamp}\n- IP Address: {ip}\n\nYour TOTP protection was bypassed for this login. The session has limited permissions for sensitive operations.\n\nIf this wasn't you, please:\n1. Change your password immediately\n2. Review your active sessions\n3. Consider disabling legacy app logins in your security settings\n\nStay safe,\n{hostname}", 65 migration_verification_subject: "Verify your email - {hostname}", 66 + migration_verification_body: "Welcome to {hostname}!\n\nYour account has been migrated successfully. To complete the setup, please verify your email address.\n\nYour verification code is:\n{code}\n\nCopy the code above and enter it at:\n{verify_page}\n\nThis code will expire in 48 hours.\n\nOr if you like to live dangerously:\n{verify_link}\n\nIf you did not migrate your account, please ignore this email.", 67 }; 68 69 static STRINGS_ZH: NotificationStrings = NotificationStrings { ··· 72 password_reset_subject: "密码重置 - {hostname}", 73 password_reset_body: "您好 @{handle},\n\n您的密码重置验证码是:{code}\n\n此验证码将在10分钟后过期。\n\n如果这不是您的操作,请忽略此消息。", 74 email_update_subject: "确认您的新邮箱 - {hostname}", 75 + email_update_body: "您好 @{handle},\n\n您的验证码是:\n{code}\n\n复制上述验证码并在此输入:\n{verify_page}\n\n此验证码将在10分钟后过期。\n\n或者直接点击链接:\n{verify_link}\n\n如果这不是您的操作,请忽略此邮件。", 76 account_deletion_subject: "账户删除请求 - {hostname}", 77 account_deletion_body: "您好 @{handle},\n\n您的账户删除确认码是:{code}\n\n此验证码将在10分钟后过期。\n\n如果这不是您的操作,请立即保护您的账户。", 78 plc_operation_subject: "{hostname} - PLC 操作令牌", ··· 82 passkey_recovery_subject: "账户恢复 - {hostname}", 83 passkey_recovery_body: "您好 @{handle},\n\n您请求恢复仅通行密钥账户的访问权限。\n\n点击以下链接设置临时密码并恢复访问:\n{url}\n\n此链接将在1小时后过期。\n\n如果这不是您的操作,请忽略此消息。您的账户仍然安全。", 84 signup_verification_subject: "验证您的账户 - {hostname}", 85 + signup_verification_body: "欢迎!您的验证码是:\n{code}\n\n复制上述验证码并在此输入:\n{verify_page}\n\n此验证码将在30分钟后过期。\n\n或者直接点击链接:\n{verify_link}\n\n如果您没有在 {hostname} 上创建账户,请忽略此消息。", 86 legacy_login_subject: "安全提醒:检测到传统应用登录 - {hostname}", 87 legacy_login_body: "您好 @{handle},\n\n检测到使用不支持 TOTP 验证的传统应用(如 Bluesky)登录您的账户。\n\n详细信息:\n- 时间:{timestamp}\n- IP 地址:{ip}\n\n此次登录绕过了 TOTP 保护。该会话对敏感操作的权限有限。\n\n如果这不是您的操作,请:\n1. 立即更改密码\n2. 检查您的活跃会话\n3. 考虑在安全设置中禁用传统应用登录\n\n请注意安全,\n{hostname}", 88 migration_verification_subject: "验证您的邮箱 - {hostname}", 89 + migration_verification_body: "欢迎来到 {hostname}!\n\n您的账户已成功迁移。要完成设置,请验证您的邮箱地址。\n\n您的验证码是:\n{code}\n\n复制上述验证码并在此输入:\n{verify_page}\n\n此验证码将在 48 小时后过期。\n\n或者直接点击链接:\n{verify_link}\n\n如果您没有迁移账户,请忽略此邮件。", 90 }; 91 92 static STRINGS_JA: NotificationStrings = NotificationStrings { ··· 95 password_reset_subject: "パスワードリセット - {hostname}", 96 password_reset_body: "@{handle} 様\n\nパスワードリセットコードは:{code}\n\nこのコードは10分後に期限切れとなります。\n\nこの操作に心当たりがない場合は、このメッセージを無視してください。", 97 email_update_subject: "新しいメールアドレスの確認 - {hostname}", 98 + email_update_body: "@{handle} 様\n\n確認コードは:\n{code}\n\n上記のコードをコピーして、こちらで入力してください:\n{verify_page}\n\nこのコードは10分後に期限切れとなります。\n\n自己責任でワンクリック認証:\n{verify_link}\n\nこの操作に心当たりがない場合は、このメールを無視してください。", 99 account_deletion_subject: "アカウント削除リクエスト - {hostname}", 100 account_deletion_body: "@{handle} 様\n\nアカウント削除の確認コードは:{code}\n\nこのコードは10分後に期限切れとなります。\n\nこの操作に心当たりがない場合は、直ちにアカウントを保護してください。", 101 plc_operation_subject: "{hostname} - PLC 操作トークン", ··· 105 passkey_recovery_subject: "アカウント復旧 - {hostname}", 106 passkey_recovery_body: "@{handle} 様\n\nパスキー専用アカウントの復旧をリクエストされました。\n\n以下のリンクをクリックして一時パスワードを設定し、アクセスを回復してください:\n{url}\n\nこのリンクは1時間後に期限切れとなります。\n\nこの操作に心当たりがない場合は、このメッセージを無視してください。アカウントは安全なままです。", 107 signup_verification_subject: "アカウント認証 - {hostname}", 108 + signup_verification_body: "ようこそ!認証コードは:\n{code}\n\n上記のコードをコピーして、こちらで入力してください:\n{verify_page}\n\nこのコードは30分後に期限切れとなります。\n\n自己責任でワンクリック認証:\n{verify_link}\n\n{hostname} でアカウントを作成していない場合は、このメールを無視してください。", 109 legacy_login_subject: "セキュリティ警告:レガシーログインを検出 - {hostname}", 110 legacy_login_body: "@{handle} 様\n\nTOTP 認証に対応していないレガシーアプリ(Bluesky など)からのログインが検出されました。\n\n詳細:\n- 時刻:{timestamp}\n- IP アドレス:{ip}\n\nこのログインでは TOTP 保護がバイパスされました。このセッションは機密操作に対する権限が制限されています。\n\n心当たりがない場合は:\n1. 直ちにパスワードを変更してください\n2. アクティブなセッションを確認してください\n3. セキュリティ設定でレガシーアプリのログインを無効にすることを検討してください\n\nご注意ください。\n{hostname}", 111 migration_verification_subject: "メールアドレスの認証 - {hostname}", 112 + migration_verification_body: "{hostname} へようこそ!\n\nアカウントの移行が完了しました。設定を完了するには、メールアドレスを認証してください。\n\n認証コードは:\n{code}\n\n上記のコードをコピーして、こちらで入力してください:\n{verify_page}\n\nこのコードは48時間後に期限切れとなります。\n\n自己責任でワンクリック認証:\n{verify_link}\n\nアカウントを移行していない場合は、このメールを無視してください。", 113 }; 114 115 static STRINGS_KO: NotificationStrings = NotificationStrings { ··· 118 password_reset_subject: "비밀번호 재설정 - {hostname}", 119 password_reset_body: "안녕하세요 @{handle}님,\n\n비밀번호 재설정 코드는: {code}\n\n이 코드는 10분 후에 만료됩니다.\n\n요청하지 않으셨다면 이 메시지를 무시하세요.", 120 email_update_subject: "새 이메일 주소 확인 - {hostname}", 121 + email_update_body: "안녕하세요 @{handle}님,\n\n인증 코드는:\n{code}\n\n위 코드를 복사하여 여기에 입력하세요:\n{verify_page}\n\n이 코드는 10분 후에 만료됩니다.\n\n위험을 감수하고 원클릭 인증:\n{verify_link}\n\n요청하지 않으셨다면 이 이메일을 무시하세요.", 122 account_deletion_subject: "계정 삭제 요청 - {hostname}", 123 account_deletion_body: "안녕하세요 @{handle}님,\n\n계정 삭제 확인 코드는: {code}\n\n이 코드는 10분 후에 만료됩니다.\n\n요청하지 않으셨다면 즉시 계정을 보호하세요.", 124 plc_operation_subject: "{hostname} - PLC 작업 토큰", ··· 128 passkey_recovery_subject: "계정 복구 - {hostname}", 129 passkey_recovery_body: "안녕하세요 @{handle}님,\n\n패스키 전용 계정 복구를 요청하셨습니다.\n\n아래 링크를 클릭하여 임시 비밀번호를 설정하고 액세스를 복구하세요:\n{url}\n\n이 링크는 1시간 후에 만료됩니다.\n\n요청하지 않으셨다면 이 메시지를 무시하세요. 계정은 안전하게 유지됩니다.", 130 signup_verification_subject: "계정 인증 - {hostname}", 131 + signup_verification_body: "환영합니다! 인증 코드는:\n{code}\n\n위 코드를 복사하여 여기에 입력하세요:\n{verify_page}\n\n이 코드는 30분 후에 만료됩니다.\n\n위험을 감수하고 원클릭 인증:\n{verify_link}\n\n{hostname}에서 계정을 만들지 않았다면 이 이메일을 무시하세요.", 132 legacy_login_subject: "보안 알림: 레거시 로그인 감지 - {hostname}", 133 legacy_login_body: "안녕하세요 @{handle}님,\n\nTOTP 인증을 지원하지 않는 레거시 앱(예: Bluesky)을 사용한 로그인이 감지되었습니다.\n\n세부 정보:\n- 시간: {timestamp}\n- IP 주소: {ip}\n\n이 로그인에서 TOTP 보호가 우회되었습니다. 이 세션은 민감한 작업에 대한 권한이 제한됩니다.\n\n본인이 아닌 경우:\n1. 즉시 비밀번호를 변경하세요\n2. 활성 세션을 검토하세요\n3. 보안 설정에서 레거시 앱 로그인 비활성화를 고려하세요\n\n{hostname} 드림", 134 migration_verification_subject: "이메일 인증 - {hostname}", 135 + migration_verification_body: "{hostname}에 오신 것을 환영합니다!\n\n계정 마이그레이션이 완료되었습니다. 설정을 완료하려면 이메일 주소를 인증하세요.\n\n인증 코드는:\n{code}\n\n위 코드를 복사하여 여기에 입력하세요:\n{verify_page}\n\n이 코드는 48시간 후에 만료됩니다.\n\n위험을 감수하고 원클릭 인증:\n{verify_link}\n\n계정을 마이그레이션하지 않았다면 이 이메일을 무시하세요.", 136 }; 137 138 static STRINGS_SV: NotificationStrings = NotificationStrings { ··· 141 password_reset_subject: "Lösenordsåterställning - {hostname}", 142 password_reset_body: "Hej @{handle},\n\nDin kod för lösenordsåterställning är: {code}\n\nDenna kod upphör om 10 minuter.\n\nOm du inte begärde detta kan du ignorera detta meddelande.", 143 email_update_subject: "Bekräfta din nya e-post - {hostname}", 144 + email_update_body: "Hej @{handle},\n\nDin verifieringskod är:\n{code}\n\nKopiera koden ovan och ange den på:\n{verify_page}\n\nDenna kod upphör om 10 minuter.\n\nEller om du gillar att leva farligt:\n{verify_link}\n\nOm du inte begärde detta kan du ignorera detta meddelande.", 145 account_deletion_subject: "Begäran om kontoradering - {hostname}", 146 account_deletion_body: "Hej @{handle},\n\nDin bekräftelsekod för kontoradering är: {code}\n\nDenna kod upphör om 10 minuter.\n\nOm du inte begärde detta, skydda ditt konto omedelbart.", 147 plc_operation_subject: "{hostname} - PLC-operationstoken", ··· 151 passkey_recovery_subject: "Kontoåterställning - {hostname}", 152 passkey_recovery_body: "Hej @{handle},\n\nDu begärde att återställa ditt endast nyckelkonto.\n\nKlicka på länken nedan för att ställa in ett tillfälligt lösenord och återfå åtkomst:\n{url}\n\nDenna länk upphör om 1 timme.\n\nOm du inte begärde detta kan du ignorera detta meddelande. Ditt konto förblir säkert.", 153 signup_verification_subject: "Verifiera ditt konto - {hostname}", 154 + signup_verification_body: "Välkommen! Din verifieringskod är:\n{code}\n\nKopiera koden ovan och ange den på:\n{verify_page}\n\nDenna kod upphör om 30 minuter.\n\nEller om du gillar att leva farligt:\n{verify_link}\n\nOm du inte skapade ett konto på {hostname}, ignorera detta meddelande.", 155 legacy_login_subject: "Säkerhetsvarning: Äldre inloggning upptäckt - {hostname}", 156 legacy_login_body: "Hej @{handle},\n\nEn inloggning till ditt konto upptäcktes med en äldre app (som Bluesky) som inte stöder TOTP-verifiering.\n\nDetaljer:\n- Tid: {timestamp}\n- IP-adress: {ip}\n\nDitt TOTP-skydd kringgicks för denna inloggning. Sessionen har begränsade behörigheter för känsliga operationer.\n\nOm detta inte var du:\n1. Ändra ditt lösenord omedelbart\n2. Granska dina aktiva sessioner\n3. Överväg att inaktivera äldre appinloggningar i dina säkerhetsinställningar\n\nVar försiktig,\n{hostname}", 157 migration_verification_subject: "Verifiera din e-post - {hostname}", 158 + migration_verification_body: "Välkommen till {hostname}!\n\nDitt konto har migrerats framgångsrikt. För att slutföra installationen, verifiera din e-postadress.\n\nDin verifieringskod är:\n{code}\n\nKopiera koden ovan och ange den på:\n{verify_page}\n\nDenna kod upphör om 48 timmar.\n\nEller om du gillar att leva farligt:\n{verify_link}\n\nOm du inte migrerade ditt konto kan du ignorera detta meddelande.", 159 }; 160 161 static STRINGS_FI: NotificationStrings = NotificationStrings { ··· 164 password_reset_subject: "Salasanan palautus - {hostname}", 165 password_reset_body: "Hei @{handle},\n\nSalasanan palautuskoodisi on: {code}\n\nTämä koodi vanhenee 10 minuutissa.\n\nJos et pyytänyt tätä, voit jättää tämän viestin huomiotta.", 166 email_update_subject: "Vahvista uusi sähköpostisi - {hostname}", 167 + email_update_body: "Hei @{handle},\n\nVahvistuskoodisi on:\n{code}\n\nKopioi koodi yllä ja syötä se osoitteessa:\n{verify_page}\n\nTämä koodi vanhenee 10 minuutissa.\n\nTai jos pidät vaarallisesta elämästä:\n{verify_link}\n\nJos et pyytänyt tätä, voit jättää tämän viestin huomiotta.", 168 account_deletion_subject: "Tilin poistopyyntö - {hostname}", 169 account_deletion_body: "Hei @{handle},\n\nTilin poiston vahvistuskoodisi on: {code}\n\nTämä koodi vanhenee 10 minuutissa.\n\nJos et pyytänyt tätä, suojaa tilisi välittömästi.", 170 plc_operation_subject: "{hostname} - PLC-toimintotunniste", ··· 174 passkey_recovery_subject: "Tilin palautus - {hostname}", 175 passkey_recovery_body: "Hei @{handle},\n\nPyysit palauttamaan vain pääsyavaintilisi.\n\nKlikkaa alla olevaa linkkiä asettaaksesi väliaikaisen salasanan ja saadaksesi pääsyn takaisin:\n{url}\n\nTämä linkki vanhenee tunnissa.\n\nJos et pyytänyt tätä, voit jättää tämän viestin huomiotta. Tilisi pysyy turvassa.", 176 signup_verification_subject: "Vahvista tilisi - {hostname}", 177 + signup_verification_body: "Tervetuloa! Vahvistuskoodisi on:\n{code}\n\nKopioi koodi yllä ja syötä se osoitteessa:\n{verify_page}\n\nTämä koodi vanhenee 30 minuutissa.\n\nTai jos pidät vaarallisesta elämästä:\n{verify_link}\n\nJos et luonut tiliä palveluun {hostname}, jätä tämä viesti huomiotta.", 178 legacy_login_subject: "Turvallisuushälytys: Vanha kirjautuminen havaittu - {hostname}", 179 legacy_login_body: "Hei @{handle},\n\nTilillesi havaittiin kirjautuminen vanhalla sovelluksella (kuten Bluesky), joka ei tue TOTP-vahvistusta.\n\nTiedot:\n- Aika: {timestamp}\n- IP-osoite: {ip}\n\nTOTP-suojauksesi ohitettiin tässä kirjautumisessa. Istunnolla on rajoitetut oikeudet arkaluontoisiin toimintoihin.\n\nJos tämä et ollut sinä:\n1. Vaihda salasanasi välittömästi\n2. Tarkista aktiiviset istuntosi\n3. Harkitse vanhojen sovellusten kirjautumisen poistamista käytöstä turvallisuusasetuksissa\n\nOle varovainen,\n{hostname}", 180 migration_verification_subject: "Vahvista sähköpostisi - {hostname}", 181 + migration_verification_body: "Tervetuloa palveluun {hostname}!\n\nTilisi on siirretty onnistuneesti. Viimeistele asennus vahvistamalla sähköpostiosoitteesi.\n\nVahvistuskoodisi on:\n{code}\n\nKopioi koodi yllä ja syötä se osoitteessa:\n{verify_page}\n\nTämä koodi vanhenee 48 tunnissa.\n\nTai jos pidät vaarallisesta elämästä:\n{verify_link}\n\nJos et siirtänyt tiliäsi, voit jättää tämän viestin huomiotta.", 182 }; 183 184 pub fn format_message(template: &str, vars: &[(&str, &str)]) -> String {
+11 -1
src/comms/sender.rs
··· 1 use async_trait::async_trait; 2 use reqwest::Client; 3 use serde_json::json; 4 use std::process::Stdio; ··· 57 value.replace(['\r', '\n'], " ").trim().to_string() 58 } 59 60 pub fn is_valid_phone_number(number: &str) -> bool { 61 if number.len() < 2 || number.len() > 20 { 62 return false; ··· 94 95 pub fn format_email(&self, notification: &QueuedComms) -> String { 96 let subject = 97 - sanitize_header_value(notification.subject.as_deref().unwrap_or("Notification")); 98 let recipient = sanitize_header_value(&notification.recipient); 99 let from_header = if self.from_name.is_empty() { 100 self.from_address.clone()
··· 1 use async_trait::async_trait; 2 + use base64::{engine::general_purpose::STANDARD as BASE64, Engine}; 3 use reqwest::Client; 4 use serde_json::json; 5 use std::process::Stdio; ··· 58 value.replace(['\r', '\n'], " ").trim().to_string() 59 } 60 61 + pub fn mime_encode_header(value: &str) -> String { 62 + if value.is_ascii() { 63 + sanitize_header_value(value) 64 + } else { 65 + let sanitized = sanitize_header_value(value); 66 + format!("=?UTF-8?B?{}?=", BASE64.encode(sanitized.as_bytes())) 67 + } 68 + } 69 + 70 pub fn is_valid_phone_number(number: &str) -> bool { 71 if number.len() < 2 || number.len() > 20 { 72 return false; ··· 104 105 pub fn format_email(&self, notification: &QueuedComms) -> String { 106 let subject = 107 + mime_encode_header(notification.subject.as_deref().unwrap_or("Notification")); 108 let recipient = sanitize_header_value(&notification.recipient); 109 let from_header = if self.from_name.is_empty() { 110 self.from_address.clone()