chore: 导入清理前的完整工程状态(含 Capacitor 原生壳,作为回滚备份点)
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import type { RedirectSsoOptions, SsoCodeExchangeOptions } from '@yunlefun/sso'
|
||||
import {
|
||||
readSsoClientId,
|
||||
readSsoRedirectUri,
|
||||
readSsoScope,
|
||||
} from '@yunlefun/sso'
|
||||
|
||||
export interface YunlefunSsoConfigInput {
|
||||
clientId?: string
|
||||
cloudbaseEnv?: string
|
||||
exchangeUrl?: string
|
||||
nativeClientId?: string
|
||||
nativeRedirectUri?: string
|
||||
redirectUri?: string
|
||||
redirectUris?: string | string[]
|
||||
scope?: string
|
||||
ssoOrigin?: string
|
||||
}
|
||||
|
||||
export interface YunlefunSsoConfigContext {
|
||||
currentOrigin: string
|
||||
platform: 'native' | 'web'
|
||||
}
|
||||
|
||||
export interface YunlefunSsoConfig {
|
||||
cloudbaseEnv: string
|
||||
exchange: SsoCodeExchangeOptions
|
||||
redirect: RedirectSsoOptions
|
||||
}
|
||||
|
||||
export type YunlefunSsoConfigResult
|
||||
= | { ok: true, config: YunlefunSsoConfig }
|
||||
| { ok: false, message: string }
|
||||
|
||||
const CLOUDBASE_ENV_RE = /^[a-z0-9][a-z0-9-]{0,63}$/i
|
||||
const TRAILING_SLASH_RE = /\/+$/
|
||||
|
||||
export function resolveYunlefunSsoConfig(
|
||||
input: YunlefunSsoConfigInput,
|
||||
context: YunlefunSsoConfigContext,
|
||||
): YunlefunSsoConfigResult {
|
||||
const clientId = readSsoClientId(
|
||||
context.platform === 'native' ? input.nativeClientId : input.clientId,
|
||||
)
|
||||
const cloudbaseEnv = normalizeValue(input.cloudbaseEnv)
|
||||
const exchangeUrl = readSsoRedirectUri(input.exchangeUrl)
|
||||
const webRedirectUris = readWebRedirectUris(input.redirectUris ?? input.redirectUri)
|
||||
const redirectUri = context.platform === 'native'
|
||||
? readSsoRedirectUri(input.nativeRedirectUri)
|
||||
: webRedirectUris.find(uri => new URL(uri).origin === context.currentOrigin)
|
||||
const scope = readSsoScope(input.scope)
|
||||
const ssoOrigin = normalizeHttpsOrigin(input.ssoOrigin)
|
||||
|
||||
if (!clientId
|
||||
|| !CLOUDBASE_ENV_RE.test(cloudbaseEnv)
|
||||
|| !exchangeUrl
|
||||
|| (context.platform === 'native' ? !redirectUri : webRedirectUris.length === 0)
|
||||
|| scope.length === 0
|
||||
|| !ssoOrigin) {
|
||||
return {
|
||||
ok: false,
|
||||
message: '登录服务尚未完成 SSO v3 配置',
|
||||
}
|
||||
}
|
||||
|
||||
if (!redirectUri) {
|
||||
return {
|
||||
ok: false,
|
||||
message: '当前域名尚未登记为登录回跳地址',
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
config: {
|
||||
cloudbaseEnv,
|
||||
exchange: { exchangeUrl },
|
||||
redirect: {
|
||||
clientId,
|
||||
redirectUri,
|
||||
scope,
|
||||
ssoOrigin,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function readWebRedirectUris(value: string | string[] | undefined): string[] {
|
||||
const candidates = Array.isArray(value)
|
||||
? value
|
||||
: typeof value === 'string'
|
||||
? value.split(/[\n,]/)
|
||||
: []
|
||||
|
||||
return [...new Set(candidates
|
||||
.map(candidate => readSsoRedirectUri(candidate.trim()))
|
||||
.filter((candidate): candidate is string => Boolean(candidate)))]
|
||||
}
|
||||
|
||||
function normalizeHttpsOrigin(value: string | undefined): string {
|
||||
const normalized = normalizeValue(value).replace(TRAILING_SLASH_RE, '')
|
||||
if (!normalized)
|
||||
return ''
|
||||
|
||||
try {
|
||||
const url = new URL(normalized)
|
||||
return url.protocol === 'https:'
|
||||
&& !url.username
|
||||
&& !url.password
|
||||
&& url.origin === normalized
|
||||
? url.origin
|
||||
: ''
|
||||
}
|
||||
catch {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeValue(value: string | undefined): string {
|
||||
return typeof value === 'string' ? value.trim() : ''
|
||||
}
|
||||
Reference in New Issue
Block a user