@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.
@@ -1,5 +1,6 @@
1
1
  import { defLoginService } from '../api/base/login'
2
- import { PasswordCryptoScene } from '../rpc/base/v1/enum'
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('当前环境不支持 Base64 解码')
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('当前环境不支持 Base64 编码')
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 mainTitle = computed(() => settingStore.getData('mainTitle') || '应用框架示例')
9
- const subTitle = computed(() => settingStore.getData('subTitle') || '保留通用导航与个人中心体验')
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">当前技术栈</text>
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">应用框架</text>
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">开发语言</text>
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">状态管理</text>
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">样式方案</text>
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">演示范围</text>
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">跨端页面</text>
56
- <text class="demo-desc">同一套页面代码适配 H5、微信小程序和 App</text>
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">账户能力</text>
63
- <text class="demo-desc">个人资料、应用设置与智能助手入口已保留</text>
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">静态首页</text>
70
- <text class="demo-desc">当前首页用于展示框架信息,不依赖业务接口</text>
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>