@liujitcn/kratos-uni-app-core 0.0.20 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/module.mjs +780 -4
- package/dist/vite.mjs +5 -3
- package/package.json +1 -1
- package/src/api/base/language.ts +25 -0
- package/src/bootstrap.ts +21 -0
- package/src/components/BootstrapStatus.vue +4 -1
- package/src/index.ts +1 -0
- package/src/locales/README.md +15 -0
- package/src/locales/en-US.json +107 -0
- package/src/locales/es-ES.json +107 -0
- package/src/locales/fr-FR.json +107 -0
- package/src/locales/generated.ts +22 -0
- package/src/locales/index.ts +216 -0
- package/src/locales/ja-JP.json +107 -0
- package/src/locales/ko-KR.json +107 -0
- package/src/locales/zh-CN.json +107 -0
- package/src/locales/zh-TW.json +107 -0
- package/src/module.ts +7 -0
- package/src/navigation.ts +58 -27
- package/src/pages.ts +3 -3
- package/src/rpc/base/v1/config.ts +14 -1
- package/src/rpc/base/v1/language.ts +31 -0
- package/src/rpc/base/v1/login.ts +14 -1
- package/src/stores/index.ts +1 -0
- package/src/stores/modules/locale.ts +28 -0
- package/src/stores/modules/setting.ts +11 -6
- package/src/utils/file.ts +19 -26
- package/src/utils/http.ts +12 -6
- package/src/utils/passwordCrypto.ts +17 -16
- package/src/views/pages/index/index.vue +16 -14
- package/src/views/pages/login/login.vue +125 -57
- package/src/views/pages/login/protocal.vue +5 -3
- package/src/views/pages/status/index.vue +16 -18
- package/src/views/pages/webview/webview.vue +6 -4
- package/src/vite.ts +4 -3
- package/src/rpc/base/v1/enum.ts +0 -54
- package/src/rpc/system/common/v1/enum.ts +0 -80
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defLoginService } from '../api/base/login'
|
|
2
|
-
import {
|
|
2
|
+
import { t } from '../locales'
|
|
3
|
+
import { PasswordCryptoScene } from '../rpc/base/v1/login'
|
|
3
4
|
import type { PasswordCrypto } from '../rpc/common/v1/types'
|
|
4
5
|
|
|
5
6
|
// #ifdef MP-WEIXIN
|
|
@@ -19,7 +20,7 @@ function pemToArrayBuffer(pem: string) {
|
|
|
19
20
|
.replace(/\s/g, '')
|
|
20
21
|
const decode = globalThis.atob
|
|
21
22
|
if (!decode) {
|
|
22
|
-
throw new Error('
|
|
23
|
+
throw new Error(t('core.crypto.base64_decode_unsupported'))
|
|
23
24
|
}
|
|
24
25
|
const binary = decode(base64)
|
|
25
26
|
const buffer = new Uint8Array(binary.length)
|
|
@@ -38,7 +39,7 @@ function arrayBufferToBase64(buffer: ArrayBuffer) {
|
|
|
38
39
|
}
|
|
39
40
|
const encode = globalThis.btoa
|
|
40
41
|
if (!encode) {
|
|
41
|
-
throw new Error('
|
|
42
|
+
throw new Error(t('core.crypto.base64_encode_unsupported'))
|
|
42
43
|
}
|
|
43
44
|
return encode(binary)
|
|
44
45
|
}
|
|
@@ -47,7 +48,7 @@ function arrayBufferToBase64(buffer: ArrayBuffer) {
|
|
|
47
48
|
function getSubtleCrypto() {
|
|
48
49
|
const cryptoApi = globalThis.crypto
|
|
49
50
|
if (!cryptoApi?.subtle) {
|
|
50
|
-
throw new Error('
|
|
51
|
+
throw new Error(t('core.crypto.unsupported'))
|
|
51
52
|
}
|
|
52
53
|
return cryptoApi
|
|
53
54
|
}
|
|
@@ -56,7 +57,7 @@ function getSubtleCrypto() {
|
|
|
56
57
|
function getMiniRandomBytes(length: number) {
|
|
57
58
|
return new Promise<ArrayBuffer>((resolve, reject) => {
|
|
58
59
|
if (typeof wx === 'undefined' || typeof wx.getRandomValues !== 'function') {
|
|
59
|
-
reject(new Error('
|
|
60
|
+
reject(new Error(t('core.crypto.unsupported')))
|
|
60
61
|
return
|
|
61
62
|
}
|
|
62
63
|
wx.getRandomValues({
|
|
@@ -65,7 +66,7 @@ function getMiniRandomBytes(length: number) {
|
|
|
65
66
|
resolve(randomValues)
|
|
66
67
|
},
|
|
67
68
|
fail: ({ errMsg }) => {
|
|
68
|
-
reject(new Error(errMsg || '
|
|
69
|
+
reject(new Error(errMsg || t('core.crypto.random_failed')))
|
|
69
70
|
},
|
|
70
71
|
})
|
|
71
72
|
})
|
|
@@ -80,7 +81,7 @@ type DerNode = {
|
|
|
80
81
|
/** 读取 DER 编码节点,用于解析 RSA SubjectPublicKeyInfo。 */
|
|
81
82
|
function readDerNode(data: Uint8Array, offset: number): DerNode {
|
|
82
83
|
if (offset + 2 > data.length) {
|
|
83
|
-
throw new Error('
|
|
84
|
+
throw new Error(t('core.crypto.public_key_invalid'))
|
|
84
85
|
}
|
|
85
86
|
const tag = data[offset]
|
|
86
87
|
const firstLengthByte = data[offset + 1]
|
|
@@ -89,7 +90,7 @@ function readDerNode(data: Uint8Array, offset: number): DerNode {
|
|
|
89
90
|
if (firstLengthByte & 0x80) {
|
|
90
91
|
const lengthByteCount = firstLengthByte & 0x7f
|
|
91
92
|
if (lengthByteCount === 0 || valueOffset + lengthByteCount > data.length) {
|
|
92
|
-
throw new Error('
|
|
93
|
+
throw new Error(t('core.crypto.public_key_invalid'))
|
|
93
94
|
}
|
|
94
95
|
length = 0
|
|
95
96
|
for (let index = 0; index < lengthByteCount; index += 1) {
|
|
@@ -99,7 +100,7 @@ function readDerNode(data: Uint8Array, offset: number): DerNode {
|
|
|
99
100
|
}
|
|
100
101
|
const end = valueOffset + length
|
|
101
102
|
if (end > data.length) {
|
|
102
|
-
throw new Error('
|
|
103
|
+
throw new Error(t('core.crypto.public_key_invalid'))
|
|
103
104
|
}
|
|
104
105
|
return {
|
|
105
106
|
tag,
|
|
@@ -128,13 +129,13 @@ function parseMiniRsaPublicKey(publicKey: string): [Uint8Array, Uint8Array] {
|
|
|
128
129
|
const algorithm = readDerNode(subjectPublicKeyInfo.value, 0)
|
|
129
130
|
const bitString = readDerNode(subjectPublicKeyInfo.value, algorithm.next)
|
|
130
131
|
if (bitString.tag !== 0x03 || bitString.value[0] !== 0) {
|
|
131
|
-
throw new Error('
|
|
132
|
+
throw new Error(t('core.crypto.public_key_invalid'))
|
|
132
133
|
}
|
|
133
134
|
const rsaPublicKey = readDerNode(bitString.value, 1)
|
|
134
135
|
const modulus = readDerNode(rsaPublicKey.value, 0)
|
|
135
136
|
const exponent = readDerNode(rsaPublicKey.value, modulus.next)
|
|
136
137
|
if (modulus.tag !== 0x02 || exponent.tag !== 0x02) {
|
|
137
|
-
throw new Error('
|
|
138
|
+
throw new Error(t('core.crypto.public_key_invalid'))
|
|
138
139
|
}
|
|
139
140
|
return [trimDerInteger(modulus.value), trimDerInteger(exponent.value)]
|
|
140
141
|
}
|
|
@@ -152,7 +153,7 @@ function generateMgf1Mask(crypto: MiniCrypto, seed: Uint8Array, length: number)
|
|
|
152
153
|
counter[3] = index
|
|
153
154
|
let block = hash.reset().process(seed).process(counter).finish().result
|
|
154
155
|
if (!block) {
|
|
155
|
-
throw new Error('
|
|
156
|
+
throw new Error(t('core.crypto.encrypt_failed'))
|
|
156
157
|
}
|
|
157
158
|
const target = mask.subarray(index * hash.HASH_SIZE)
|
|
158
159
|
if (block.length > target.length) {
|
|
@@ -189,14 +190,14 @@ async function encryptMiniProgramPassword(
|
|
|
189
190
|
const dataBlockLength = keySize - hash.HASH_SIZE - 1
|
|
190
191
|
const paddingLength = dataBlockLength - aesKey.length - hash.HASH_SIZE - 1
|
|
191
192
|
if (paddingLength < 0) {
|
|
192
|
-
throw new Error('
|
|
193
|
+
throw new Error(t('core.crypto.password_too_long'))
|
|
193
194
|
}
|
|
194
195
|
const encodedMessage = new Uint8Array(keySize)
|
|
195
196
|
const maskedSeed = encodedMessage.subarray(1, hash.HASH_SIZE + 1)
|
|
196
197
|
const dataBlock = encodedMessage.subarray(hash.HASH_SIZE + 1)
|
|
197
198
|
const labelHash = hash.reset().process(new Uint8Array()).finish().result
|
|
198
199
|
if (!labelHash) {
|
|
199
|
-
throw new Error('
|
|
200
|
+
throw new Error(t('core.crypto.encrypt_failed'))
|
|
200
201
|
}
|
|
201
202
|
dataBlock.set(labelHash, 0)
|
|
202
203
|
dataBlock.set(aesKey, hash.HASH_SIZE + paddingLength + 1)
|
|
@@ -214,7 +215,7 @@ async function encryptMiniProgramPassword(
|
|
|
214
215
|
new crypto.BigNumber(encodedMessage),
|
|
215
216
|
).result
|
|
216
217
|
if (!encryptedKey) {
|
|
217
|
-
throw new Error('
|
|
218
|
+
throw new Error(t('core.crypto.encrypt_failed'))
|
|
218
219
|
}
|
|
219
220
|
const ciphertext = crypto.AES_GCM.encrypt(plaintext, aesKey, iv)
|
|
220
221
|
return {
|
|
@@ -234,7 +235,7 @@ export async function encryptPassword(
|
|
|
234
235
|
): Promise<PasswordCrypto> {
|
|
235
236
|
const plainPassword = password.trim()
|
|
236
237
|
if (!plainPassword) {
|
|
237
|
-
throw new Error('
|
|
238
|
+
throw new Error(t('core.crypto.password_required'))
|
|
238
239
|
}
|
|
239
240
|
|
|
240
241
|
const publicKeyResponse = await defLoginService.PasswordPublicKey({ scene })
|
|
@@ -3,10 +3,12 @@ import { onLoad } from '@dcloudio/uni-app'
|
|
|
3
3
|
import { computed } from 'vue'
|
|
4
4
|
import { useSettingStore } from '../../../stores'
|
|
5
5
|
import defaultLogo from '../../../static/images/logo_icon.png'
|
|
6
|
+
import { useI18n } from '../../../locales'
|
|
6
7
|
|
|
7
8
|
const settingStore = useSettingStore()
|
|
8
|
-
const
|
|
9
|
-
const
|
|
9
|
+
const { t } = useI18n()
|
|
10
|
+
const mainTitle = computed(() => settingStore.getData('mainTitle') || t('core.home.main_title'))
|
|
11
|
+
const subTitle = computed(() => settingStore.getData('subTitle') || t('core.home.sub_title'))
|
|
10
12
|
const appLogo = computed(() => settingStore.getData('appLogo') || defaultLogo)
|
|
11
13
|
|
|
12
14
|
onLoad(() => {
|
|
@@ -25,49 +27,49 @@ onLoad(() => {
|
|
|
25
27
|
</view>
|
|
26
28
|
|
|
27
29
|
<view class="section">
|
|
28
|
-
<text class="section-title"
|
|
30
|
+
<text class="section-title">{{ t('core.home.tech_stack') }}</text>
|
|
29
31
|
<view class="info-list">
|
|
30
32
|
<view class="info-row">
|
|
31
|
-
<text class="info-label"
|
|
33
|
+
<text class="info-label">{{ t('core.home.framework') }}</text>
|
|
32
34
|
<text class="info-value">uni-app + Vue 3</text>
|
|
33
35
|
</view>
|
|
34
36
|
<view class="info-row">
|
|
35
|
-
<text class="info-label"
|
|
37
|
+
<text class="info-label">{{ t('core.home.language') }}</text>
|
|
36
38
|
<text class="info-value">TypeScript</text>
|
|
37
39
|
</view>
|
|
38
40
|
<view class="info-row">
|
|
39
|
-
<text class="info-label"
|
|
41
|
+
<text class="info-label">{{ t('core.home.state_management') }}</text>
|
|
40
42
|
<text class="info-value">Pinia</text>
|
|
41
43
|
</view>
|
|
42
44
|
<view class="info-row">
|
|
43
|
-
<text class="info-label"
|
|
45
|
+
<text class="info-label">{{ t('core.home.style_solution') }}</text>
|
|
44
46
|
<text class="info-value">Sass + rpx</text>
|
|
45
47
|
</view>
|
|
46
48
|
</view>
|
|
47
49
|
</view>
|
|
48
50
|
|
|
49
51
|
<view class="section">
|
|
50
|
-
<text class="section-title"
|
|
52
|
+
<text class="section-title">{{ t('core.home.demo_scope') }}</text>
|
|
51
53
|
<view class="demo-list">
|
|
52
54
|
<view class="demo-item">
|
|
53
55
|
<view class="demo-dot">1</view>
|
|
54
56
|
<view class="demo-copy">
|
|
55
|
-
<text class="demo-title"
|
|
56
|
-
<text class="demo-desc"
|
|
57
|
+
<text class="demo-title">{{ t('core.home.cross_platform') }}</text>
|
|
58
|
+
<text class="demo-desc">{{ t('core.home.cross_platform_description') }}</text>
|
|
57
59
|
</view>
|
|
58
60
|
</view>
|
|
59
61
|
<view class="demo-item">
|
|
60
62
|
<view class="demo-dot">2</view>
|
|
61
63
|
<view class="demo-copy">
|
|
62
|
-
<text class="demo-title"
|
|
63
|
-
<text class="demo-desc"
|
|
64
|
+
<text class="demo-title">{{ t('core.home.account_capability') }}</text>
|
|
65
|
+
<text class="demo-desc">{{ t('core.home.account_capability_description') }}</text>
|
|
64
66
|
</view>
|
|
65
67
|
</view>
|
|
66
68
|
<view class="demo-item">
|
|
67
69
|
<view class="demo-dot">3</view>
|
|
68
70
|
<view class="demo-copy">
|
|
69
|
-
<text class="demo-title"
|
|
70
|
-
<text class="demo-desc"
|
|
71
|
+
<text class="demo-title">{{ t('core.home.static_home') }}</text>
|
|
72
|
+
<text class="demo-desc">{{ t('core.home.static_home_description') }}</text>
|
|
71
73
|
</view>
|
|
72
74
|
</view>
|
|
73
75
|
</view>
|