add asset sample
Signed-off-by: 尹耀德 <yinyaode1@huawei.com>
11
OAT.xml
@ -103,6 +103,17 @@ Note:If the text contains special characters, please escape them according to th
|
||||
<filteritem type="filepath" name="network/Bluetooth/entry/src/main/java/ohos/samples/bluetooth/adapter/" desc="Not contains 3rd code,license file is not required in this subdirectory."/>
|
||||
</filefilter>
|
||||
<filefilter name="binaryFileTypePolicyFilter" desc="Filters for binary file policies" >
|
||||
<filteritem type="filepath" name="code/BasicFeature/Security/Asset/AppScope/resources/base/media/app_icon.png" desc="Provided by the UX team."/>
|
||||
<filteritem type="filepath" name="code/BasicFeature/Security/Asset/AppScope/resources/base/media/forward.png" desc="Provided by the UX team."/>
|
||||
<filteritem type="filepath" name="code/BasicFeature/Security/Asset/AppScope/resources/base/media/back.png" desc="Provided by the UX team."/>
|
||||
<filteritem type="filepath" name="code/BasicFeature/Security/Asset/entry/src/ohosTest/resources/base/media/icon.png" desc="Provided by the UX team."/>
|
||||
<filteritem type="filepath" name="code/BasicFeature/Security/Asset/screenshots/update_edit.jpeg" desc="screenshot"/>
|
||||
<filteritem type="filepath" name="code/BasicFeature/Security/Asset/screenshots/single_query_result.jpeg" desc="screenshot"/>
|
||||
<filteritem type="filepath" name="code/BasicFeature/Security/Asset/screenshots/update_list.jpeg" desc="screenshot"/>
|
||||
<filteritem type="filepath" name="code/BasicFeature/Security/Asset/screenshots/delete.jpeg" desc="screenshot"/>
|
||||
<filteritem type="filepath" name="code/BasicFeature/Security/Asset/screenshots/save.jpeg" desc="screenshot"/>
|
||||
<filteritem type="filepath" name="code/BasicFeature/Security/Asset/screenshots/batch_query_result.jpeg" desc="screenshot"/>
|
||||
<filteritem type="filepath" name="code/BasicFeature/Security/Asset/screenshots/query.jpeg" desc="screenshot"/>
|
||||
<filteritem type="filepath" name="ability/DistributedMusicPlayer/entry/src/main/resources/rawfile/Homey.mp3" desc="Provided by the UX team."/>
|
||||
<filteritem type="filepath" name="ability/DistributedMusicPlayer/entry/src/main/resources/rawfile/Technology.mp3" desc="Provided by the UX team."/>
|
||||
<filteritem type="filepath" name="UI/JsAnimation/entry/src/main/js/default/common/animator/show.mp4" desc="Provided by the UX team."/>
|
||||
|
@ -118,6 +118,7 @@
|
||||
<td x:str><a href="code/BasicFeature/Security/Huks">通用密钥库系统(huks)(API 10)</a></td>
|
||||
<td x:str><a href="code/BasicFeature/Security/PaySecurely">支付</a></td>
|
||||
<td x:str><a href="code/BasicFeature/Security/CertManager">证书管理</a></td>
|
||||
<td x:str><a href="code/BasicFeature/Security/Asset">关键资产存储</a></td>
|
||||
<td ></td>
|
||||
</tr>
|
||||
<tr height="18" style='height:13.50pt;'>
|
||||
|
11
code/BasicFeature/Security/Asset/.gitignore
vendored
Executable file
@ -0,0 +1,11 @@
|
||||
/node_modules
|
||||
/oh_modules
|
||||
/local.properties
|
||||
/.idea
|
||||
**/build
|
||||
/.hvigor
|
||||
.cxx
|
||||
/.clangd
|
||||
/.clang-format
|
||||
/.clang-tidy
|
||||
**/.test
|
25
code/BasicFeature/Security/Asset/AppScope/app.json5
Executable file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
{
|
||||
"app": {
|
||||
"bundleName": "com.example.asset_sample",
|
||||
"vendor": "example",
|
||||
"versionCode": 1000000,
|
||||
"versionName": "1.0.0",
|
||||
"icon": "$media:app_icon",
|
||||
"label": "$string:app_name"
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "app_name",
|
||||
"value": "asset_sample"
|
||||
}
|
||||
]
|
||||
}
|
BIN
code/BasicFeature/Security/Asset/AppScope/resources/base/media/app_icon.png
Executable file
After Width: | Height: | Size: 2.0 KiB |
BIN
code/BasicFeature/Security/Asset/AppScope/resources/base/media/back.png
Executable file
After Width: | Height: | Size: 529 B |
BIN
code/BasicFeature/Security/Asset/AppScope/resources/base/media/forward.png
Executable file
After Width: | Height: | Size: 502 B |
110
code/BasicFeature/Security/Asset/README_zh.md
Executable file
@ -0,0 +1,110 @@
|
||||
# 关键资产存储服务
|
||||
## 介绍
|
||||
本示例使用@kit.AssetStoreKit相关接口实现了对敏感数据的保存、更新、查询、删除操作。
|
||||
|
||||
实现场景如下:
|
||||
|
||||
1)用户使用本应用保存密码或信用卡号。
|
||||
|
||||
2)用户更新本应用管理的密码或信用卡号。
|
||||
|
||||
3)用户查询本应用管理的密码或信用卡号。
|
||||
|
||||
4)用户删除本应用管理的密码或信用卡号。
|
||||
|
||||
## 效果预览
|
||||
| **保存页面** | **删除页面** | **更新列表页面** | **更新编辑页面** |
|
||||
|---------|----------|------------|----------|
|
||||
|![](screenshots/save.jpeg)|![](screenshots/delete.jpeg)|![](screenshots/update_list.jpeg)|![](screenshots/update_edit.jpeg)|
|
||||
| **查询页面** | **批量查询结果页面** | **单个查询结果页面** |
|
||||
![](screenshots/query.jpeg)|![](screenshots/batch_query_result.jpeg)|![](screenshots/single_query_result.jpeg)|
|
||||
|
||||
使用说明:
|
||||
* 保存敏感数据:
|
||||
* 输入账号、密码、标签,其中标签可以填写多个,但不超过4个
|
||||
* 点击“保存”按钮
|
||||
|
||||
* 删除敏感数据,可使用以下任意一种方式删除:
|
||||
* 批量删除:不输入任何信息,或输入单个或多个标签),点击“删除”按钮
|
||||
* 单个删除:输入账号、标签(可选),点击“删除”按钮
|
||||
* 更新敏感数据:
|
||||
* 点击标题栏的“更新”,进入更新页面
|
||||
* 在显示的账号列表中,点击待更新的账号
|
||||
* 输入锁屏密码,进入编辑界面
|
||||
* 输入更新后的密码和标签,点击“更新”
|
||||
* 查询敏感数据,可使用以下任意一种方式删除:
|
||||
* 批量查询:不输入任何信息,或输入单个或多个标签),点击“查询”按钮,显示保存的信息列表,不含“密码/信用卡号”
|
||||
* 单个查询:输入账号、标签(可选),点击“查询”按钮,输入锁屏密码,显示该账号详细信息,含“密码/信用卡号”
|
||||
|
||||
## 工程目录
|
||||
```
|
||||
entry/src/main/ets/
|
||||
|---entryAbility
|
||||
| |---EntryAbility.ts
|
||||
|---model
|
||||
| |---AssetModel.ets // 关键资产存储模型文件
|
||||
|---pages
|
||||
| |---Index.ets // 主页面
|
||||
| |---QueryResultPage.ets // 查询结果界面
|
||||
| |---UpdatePage.ets // 更新页面
|
||||
```
|
||||
## 具体实现
|
||||
本应用分为四个主页面:保存、删除、更新、查询,通过TabBuilder组件实现页面直接的切换。
|
||||
* **保存页面**:解析用户输入的账号、密码、标签信息,传入@kit.AssetStoreKit提供的add接口,从而实现将短敏感数据存储到关键资产存储服务中。
|
||||
|
||||
* **删除页面**:解析用户输入的账号、标签信息,传入@kit.AssetStoreKit提供的remove接口,删除满足条件的短敏感数据。
|
||||
|
||||
* **更新页面**:
|
||||
|
||||
1)调用@kit.AssetStoreKit提供的query接口,查询关键资产中存储的全量账号。
|
||||
|
||||
2)调用@kit.AssetStoreKit提供的preQuery接口,将返回的challenge传给@kit.UserAuthenticationKit提供的on接口。
|
||||
|
||||
3)待用户输入锁屏密码后,将onResult接口返回的AuthToken传给@kit.AssetStoreKit提供的query接口,用以查询旧的敏感数据明文。
|
||||
|
||||
4)解析用户输入的账号、标签信息,传入@kit.AssetStoreKit提供的update接口,更新关键资产存储服务中存储的敏感数据。
|
||||
|
||||
5)退出更新界面时,调用@kit.AssetStoreKit提供的postQuery接口清理资源
|
||||
|
||||
* **查询页面**:
|
||||
|
||||
用户未输入账号:
|
||||
|
||||
解析用户输入的标签信息,传入@kit.AssetStoreKit提供的query接口,查询关键资产存储服务中存储的账号、标签。
|
||||
|
||||
用户输入了账号:
|
||||
|
||||
1)调用@kit.AssetStoreKit提供的preQuery接口,将返回的challenge传给@kit.UserAuthenticationKit提供的on接口。
|
||||
|
||||
2)待用户输入锁屏密码后,将onResult接口返回的AuthToken、用户输入的账号、标签信息传给@kit.AssetStoreKit提供的query接口,用以查询敏感数据明文。
|
||||
|
||||
3)调用@kit.AssetStoreKit提供的postQuery接口清理资源。
|
||||
|
||||
## 相关权限
|
||||
ohos.permission.ACCESS_BIOMETRIC
|
||||
|
||||
ohos.permission.STORE_PERSISTENT_DATA
|
||||
|
||||
## 依赖
|
||||
不涉及
|
||||
|
||||
## 约束与限制
|
||||
1.本示例仅支持标准系统上运行。
|
||||
|
||||
2.本示例支持API11版本SDK,SDK版本号(API Version 11 Release), 镜像版本号(4.1Release)。
|
||||
|
||||
3.本示例需要使用DevEco Studio版本号(4.1Release)及以上版本才可编译运行。
|
||||
|
||||
4.本示例需要在设备设置锁屏密码后使用。其中,更新、查询结果页面输入锁屏密码方可进入。
|
||||
|
||||
## 下载
|
||||
如需单独下载本工程,执行如下命令:
|
||||
|
||||
```
|
||||
git init
|
||||
git config core.sparsecheckout true
|
||||
echo code/BasicFeature/Security/Asset/ > .git/info/sparse-checkout
|
||||
git remote add origin https://gitee.com/openharmony/applications_app_samples.git
|
||||
git pull origin master
|
||||
|
||||
```
|
56
code/BasicFeature/Security/Asset/build-profile.json5
Executable file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
{
|
||||
"app": {
|
||||
"products": [
|
||||
{
|
||||
"name": "default",
|
||||
"signingConfig": "default",
|
||||
"compileSdkVersion": 11,
|
||||
"compatibleSdkVersion": 11,
|
||||
"runtimeOS": "OpenHarmony"
|
||||
}
|
||||
],
|
||||
"signingConfigs": [
|
||||
{
|
||||
"name": "default",
|
||||
"material": {
|
||||
"certpath": "C:/Users/zengbenchong/.ohos/config/openharmony/default_Asset_WMjW1k3aXdGTv9zVP9gZHS6Q095UiwPg2bW9aR_b0Gw=.cer",
|
||||
"storePassword": "0000001B53993973AD492CF6E3976586BBED74A3A3E4D725B2C0CDC71D63D0522A290CC9E86C861E213C97",
|
||||
"keyAlias": "debugKey",
|
||||
"keyPassword": "0000001B5B410B8FCF1DFC802D233B1A0AC012B8294A5BFB3BF3713733C3B5E2B68C890DC235987A625118",
|
||||
"profile": "C:/Users/zengbenchong/.ohos/config/openharmony/default_Asset_WMjW1k3aXdGTv9zVP9gZHS6Q095UiwPg2bW9aR_b0Gw=.p7b",
|
||||
"signAlg": "SHA256withECDSA",
|
||||
"storeFile": "C:/Users/zengbenchong/.ohos/config/openharmony/default_Asset_WMjW1k3aXdGTv9zVP9gZHS6Q095UiwPg2bW9aR_b0Gw=.p12"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"name": "entry",
|
||||
"srcPath": "./entry",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
6
code/BasicFeature/Security/Asset/entry/.gitignore
vendored
Executable file
@ -0,0 +1,6 @@
|
||||
/node_modules
|
||||
/oh_modules
|
||||
/.preview
|
||||
/build
|
||||
/.cxx
|
||||
/.test
|
27
code/BasicFeature/Security/Asset/entry/build-profile.json5
Executable file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
{
|
||||
"apiType": 'stageMode',
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"runtimeOS": "OpenHarmony"
|
||||
},
|
||||
{
|
||||
"name": "ohosTest",
|
||||
}
|
||||
]
|
||||
}
|
6
code/BasicFeature/Security/Asset/entry/hvigorfile.ts
Executable file
@ -0,0 +1,6 @@
|
||||
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
|
||||
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
|
||||
}
|
11
code/BasicFeature/Security/Asset/entry/oh-package.json5
Executable file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"license": "",
|
||||
"devDependencies": {},
|
||||
"author": "",
|
||||
"name": "entry",
|
||||
"description": "Please describe the basic information.",
|
||||
"main": "",
|
||||
"version": "1.0.0",
|
||||
"dynamicDependencies": {},
|
||||
"dependencies": {}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AbilityConstant } from '@kit.AbilityKit';
|
||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||
import { UIAbility } from '@kit.AbilityKit';
|
||||
import { Want } from '@kit.AbilityKit';
|
||||
import { window } from '@kit.ArkUI';
|
||||
|
||||
export default class EntryAbility extends UIAbility {
|
||||
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
|
||||
}
|
||||
|
||||
onWindowStageCreate(windowStage: window.WindowStage) {
|
||||
// Main window is created, set main page for this ability
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
|
||||
|
||||
windowStage.loadContent('pages/Index', (err, data) => {
|
||||
if (err.code) {
|
||||
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
|
||||
return;
|
||||
}
|
||||
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
|
||||
});
|
||||
}
|
||||
|
||||
onWindowStageDestroy() {
|
||||
// Main window is destroyed, release UI related resources
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
|
||||
}
|
||||
|
||||
onForeground() {
|
||||
// Ability has brought to foreground
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
|
||||
}
|
||||
|
||||
onBackground() {
|
||||
// Ability has back to background
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
|
||||
}
|
||||
}
|
329
code/BasicFeature/Security/Asset/entry/src/main/ets/model/AssetModel.ets
Executable file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { asset } from '@kit.AssetStoreKit';
|
||||
import { promptAction } from '@kit.ArkUI';
|
||||
import { util } from '@kit.ArkTS';
|
||||
|
||||
function removeDuplicateAndSort(arr: string[]): string[] {
|
||||
let newArr = new Array<string>();
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
if (newArr.indexOf(arr[i]) === -1 && arr[i] != '') {
|
||||
newArr.push(arr[i]);
|
||||
}
|
||||
}
|
||||
return newArr.sort();
|
||||
}
|
||||
|
||||
export function log(str: string) {
|
||||
promptAction.showToast({ message: str })
|
||||
console.log(str);
|
||||
}
|
||||
|
||||
export function stringToArray(str: string): Uint8Array {
|
||||
let textEncoder = new util.TextEncoder();
|
||||
return textEncoder.encodeInto(str);
|
||||
}
|
||||
|
||||
function newNullArray(): Uint8Array {
|
||||
return new Uint8Array([0]);
|
||||
}
|
||||
|
||||
function arrayToString(arr: Uint8Array): string {
|
||||
let textDecoder = util.TextDecoder.create("utf-8", {
|
||||
ignoreBOM: true
|
||||
});
|
||||
let str = textDecoder.decodeWithStream(arr, {
|
||||
stream: false
|
||||
})
|
||||
return str;
|
||||
}
|
||||
|
||||
export async function addAssetPromise(account: string, password: string, label: string) {
|
||||
let labelList: Array<string> = label.split(';');
|
||||
labelList = removeDuplicateAndSort(labelList);
|
||||
if (labelList.length > 4) {
|
||||
log("保存失败,标签数量超过4个")
|
||||
return;
|
||||
}
|
||||
let attr: asset.AssetMap = new Map();
|
||||
attr.set(asset.Tag.ALIAS, stringToArray(account))
|
||||
attr.set(asset.Tag.SECRET, stringToArray(password))
|
||||
if (labelList[0]) {
|
||||
attr.set(asset.Tag.DATA_LABEL_NORMAL_1, stringToArray(labelList[0]))
|
||||
}
|
||||
if (labelList[1]) {
|
||||
attr.set(asset.Tag.DATA_LABEL_NORMAL_2, stringToArray(labelList[1]))
|
||||
}
|
||||
if (labelList[2]) {
|
||||
attr.set(asset.Tag.DATA_LABEL_NORMAL_3, stringToArray(labelList[2]))
|
||||
}
|
||||
if (labelList[3]) {
|
||||
attr.set(asset.Tag.DATA_LABEL_NORMAL_4, stringToArray(labelList[3]))
|
||||
}
|
||||
attr.set(asset.Tag.AUTH_TYPE, asset.AuthType.ANY)
|
||||
attr.set(asset.Tag.IS_PERSISTENT, true)
|
||||
try {
|
||||
await asset.add(attr);
|
||||
log("保存成功")
|
||||
} catch (error) {
|
||||
if (error.code === 24000003) {
|
||||
log('保存失败,账号已存在');
|
||||
} else {
|
||||
log('保存失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeAssetPromise(deleteAccount: string, deleteLabel: string) {
|
||||
let attr: asset.AssetMap = new Map();
|
||||
if (deleteAccount.length > 0) {
|
||||
attr.set(asset.Tag.ALIAS, stringToArray(deleteAccount))
|
||||
}
|
||||
if (deleteLabel.length == 0) {
|
||||
try {
|
||||
await asset.remove(attr);
|
||||
log("删除成功")
|
||||
} catch (error) {
|
||||
if (error.code === 24000002) {
|
||||
log('删除失败,账号不存在');
|
||||
} else {
|
||||
log('删除失败')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let labelList = deleteLabel.split(';');
|
||||
labelList = removeDuplicateAndSort(labelList);
|
||||
let assetList: asset.AssetMap[] = await getArrangedMap(deleteAccount, labelList)
|
||||
if (assetList.length == 0) {
|
||||
log('删除失败,账号不存在');
|
||||
return;
|
||||
}
|
||||
let map: Map<asset.Tag, asset.Value> = new Map();
|
||||
for (let i = 0; i < assetList.length; i++) {
|
||||
map.set(asset.Tag.ALIAS, assetList[i].get(asset.Tag.ALIAS) as Uint8Array);
|
||||
try {
|
||||
await asset.remove(map)
|
||||
} catch (error) {
|
||||
log('删除失败')
|
||||
return;
|
||||
}
|
||||
}
|
||||
log("删除成功")
|
||||
}
|
||||
}
|
||||
|
||||
function compareArray(array1: Uint8Array, array2: Uint8Array): boolean {
|
||||
return JSON.stringify(array1) == JSON.stringify(array2);
|
||||
}
|
||||
|
||||
function addLabelInfo(label: string, tag: asset.Tag, account: asset.AssetMap, emptyArray: Uint8Array): string {
|
||||
if (account.has(tag) && !compareArray(account.get(tag) as Uint8Array, emptyArray)) {
|
||||
label += arrayToString(account.get(tag) as Uint8Array) + ';'
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
function addElement(attr: asset.AssetMap, label: string, key: asset.Tag) {
|
||||
if (label){
|
||||
attr.set(key, stringToArray(label))
|
||||
} else {
|
||||
attr.set(key, newNullArray())
|
||||
}
|
||||
}
|
||||
|
||||
let normalLabelList: Array<asset.Tag> = new Array<asset.Tag>(asset.Tag.DATA_LABEL_NORMAL_1,
|
||||
asset.Tag.DATA_LABEL_NORMAL_2, asset.Tag.DATA_LABEL_NORMAL_3, asset.Tag.DATA_LABEL_NORMAL_4);
|
||||
|
||||
// asset获取的map转换为显示map
|
||||
function convertAssetList(assetList: asset.AssetMap[], accountList: Map<string, string>[]): Array<Map<string, string>> {
|
||||
for (let account of assetList) {
|
||||
let map: Map<string, string> = new Map<string, string>();
|
||||
let alias = arrayToString(account.get(asset.Tag.ALIAS) as Uint8Array);
|
||||
if (account.has(asset.Tag.SECRET)) {
|
||||
let secret = arrayToString(account.get(asset.Tag.SECRET) as Uint8Array);
|
||||
map.set('secret', secret);
|
||||
}
|
||||
let label = ''
|
||||
let emptyArray = newNullArray();
|
||||
for (let currentLabel of normalLabelList) {
|
||||
label = addLabelInfo(label, currentLabel, account, emptyArray);
|
||||
}
|
||||
label = label.slice(0, label.length - 1)
|
||||
map.set('alias', alias);
|
||||
map.set('label', label)
|
||||
accountList.push(map);
|
||||
}
|
||||
return accountList;
|
||||
}
|
||||
|
||||
export async function updateAssetPromise(reserveAccount: string, reservePassword: string, reserveLabel: string) {
|
||||
let labelList = reserveLabel.split(';');
|
||||
labelList = removeDuplicateAndSort(labelList);
|
||||
if (labelList.length > 4) {
|
||||
log("更新失败,标签数量超过4个")
|
||||
return;
|
||||
}
|
||||
|
||||
let attr: asset.AssetMap = new Map();
|
||||
attr.set(asset.Tag.SECRET, stringToArray(reservePassword))
|
||||
normalLabelList.forEach((element: asset.Tag, index: number) => {
|
||||
addElement(attr, labelList[index], element);
|
||||
});
|
||||
|
||||
let attr2: asset.AssetMap = new Map();
|
||||
attr2.set(asset.Tag.ALIAS, stringToArray(reserveAccount))
|
||||
|
||||
try {
|
||||
await asset.update(attr2, attr)
|
||||
log("更新成功")
|
||||
} catch (error) {
|
||||
log('更新失败');
|
||||
}
|
||||
}
|
||||
|
||||
async function getFirstQuery(alias: string, label: string): Promise<asset.AssetMap[]>
|
||||
{
|
||||
let res: Array<asset.AssetMap> = new Array<asset.AssetMap>();
|
||||
let options: asset.Tag[] = [ asset.Tag.DATA_LABEL_NORMAL_1, asset.Tag.DATA_LABEL_NORMAL_2,
|
||||
asset.Tag.DATA_LABEL_NORMAL_3, asset.Tag.DATA_LABEL_NORMAL_4 ];
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
let map: asset.AssetMap = new Map();
|
||||
if (alias.length > 0) {
|
||||
map.set(asset.Tag.ALIAS, stringToArray(alias));
|
||||
map.set(asset.Tag.RETURN_TYPE, asset.ReturnType.ALL)
|
||||
}
|
||||
map.set(options[i], stringToArray(label));
|
||||
try {
|
||||
let temp: Array<asset.AssetMap> = await asset.query(map)
|
||||
res = res.concat(temp);
|
||||
} catch(e) {
|
||||
// skip the error: not found
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function getLabelList(input: asset.AssetMap): Array<string>
|
||||
{
|
||||
let tmp = new Array<string>();
|
||||
if (input.has(asset.Tag.DATA_LABEL_NORMAL_1)) {
|
||||
tmp.push(arrayToString(input.get(asset.Tag.DATA_LABEL_NORMAL_1) as Uint8Array));
|
||||
}
|
||||
if (input.has(asset.Tag.DATA_LABEL_NORMAL_2)) {
|
||||
tmp.push(arrayToString(input.get(asset.Tag.DATA_LABEL_NORMAL_2) as Uint8Array));
|
||||
}
|
||||
if (input.has(asset.Tag.DATA_LABEL_NORMAL_3)) {
|
||||
tmp.push(arrayToString(input.get(asset.Tag.DATA_LABEL_NORMAL_3) as Uint8Array));
|
||||
}
|
||||
if (input.has(asset.Tag.DATA_LABEL_NORMAL_4)) {
|
||||
tmp.push(arrayToString(input.get(asset.Tag.DATA_LABEL_NORMAL_4) as Uint8Array));
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
async function getArrangedMap(alias: string, labels: string[]): Promise<asset.AssetMap[]>
|
||||
{
|
||||
let first_query: asset.AssetMap[] = await getFirstQuery(alias, labels[0]);
|
||||
let res: asset.AssetMap[] = first_query.filter((map: asset.AssetMap) => {
|
||||
let list: Array<string> = getLabelList(map);
|
||||
for (let i = 1; i < labels.length; i++) {
|
||||
if (list.indexOf(labels[i]) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
export async function queryAssetPromise(checkAccount: string, checkLabel: string): Promise<Array<Map<string, string>>> {
|
||||
let accountList: Map<string, string>[] = new Array<Map<string, string>>();
|
||||
let assetMap: asset.AssetMap = new Map();
|
||||
if (checkAccount.length > 0) {
|
||||
assetMap.set(asset.Tag.ALIAS, stringToArray(checkAccount))
|
||||
assetMap.set(asset.Tag.RETURN_TYPE, asset.ReturnType.ALL)
|
||||
}
|
||||
if (checkLabel.length == 0) { // query condition do not contain label.
|
||||
try {
|
||||
let assetList: Array<asset.AssetMap> = await asset.query(assetMap);
|
||||
return convertAssetList(assetList, accountList);
|
||||
} catch (error) {
|
||||
if (error.code === 24000002) {
|
||||
log('未查询到结果');
|
||||
} else {
|
||||
log('查询失败');
|
||||
}
|
||||
return new Array<Map<string, string>>();
|
||||
}
|
||||
} else {
|
||||
let labelList: Array<string> = checkLabel.split(';');
|
||||
labelList = removeDuplicateAndSort(labelList);
|
||||
let assetList: asset.AssetMap[] = await getArrangedMap(checkAccount, labelList)
|
||||
if (assetList.length == 0) {
|
||||
log('未查询到结果');
|
||||
return new Array<Map<string, string>>();
|
||||
}
|
||||
return convertAssetList(assetList, accountList);
|
||||
}
|
||||
}
|
||||
|
||||
export async function preQueryAssetPromise(checkAccount: string): Promise<Uint8Array> {
|
||||
let assetMap: asset.AssetMap = new Map();
|
||||
assetMap.set(asset.Tag.AUTH_VALIDITY_PERIOD, 10 * 60)
|
||||
assetMap.set(asset.Tag.AUTH_TYPE, asset.AuthType.ANY)
|
||||
if (checkAccount.length > 0) {
|
||||
assetMap.set(asset.Tag.ALIAS, stringToArray(checkAccount))
|
||||
}
|
||||
try {
|
||||
return await asset.preQuery(assetMap)
|
||||
} catch (error) {
|
||||
return new Uint8Array(0)
|
||||
}
|
||||
}
|
||||
|
||||
export async function queryAuthAssetPromise(checkAccount: string, challenge: Uint8Array,
|
||||
authToken: Uint8Array): Promise<Map<string, string>> {
|
||||
let attr: asset.AssetMap = new Map();
|
||||
let account: Map<string, string> = new Map<string, string>();
|
||||
if (checkAccount.length > 0) {
|
||||
attr.set(asset.Tag.ALIAS, stringToArray(checkAccount));
|
||||
attr.set(asset.Tag.RETURN_TYPE, asset.ReturnType.ALL);
|
||||
attr.set(asset.Tag.AUTH_CHALLENGE, challenge);
|
||||
attr.set(asset.Tag.AUTH_TOKEN, authToken)
|
||||
}
|
||||
try {
|
||||
let data: Array<asset.AssetMap> = await asset.query(attr);
|
||||
let accountList: Map<string, string>[] = new Array<Map<string, string>>();
|
||||
accountList = convertAssetList(data, accountList);
|
||||
return accountList[0]
|
||||
} catch (error) {
|
||||
if (error.code === 24000002) {
|
||||
log('未查询到结果');
|
||||
} else {
|
||||
log('查询失败');
|
||||
}
|
||||
return account;
|
||||
}
|
||||
}
|
||||
|
||||
export async function postQueryAssetPromise(challenge: Uint8Array) {
|
||||
let attr: asset.AssetMap = new Map();
|
||||
attr.set(asset.Tag.AUTH_CHALLENGE, challenge);
|
||||
try {
|
||||
await asset.postQuery(attr);
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
693
code/BasicFeature/Security/Asset/entry/src/main/ets/pages/Index.ets
Executable file
@ -0,0 +1,693 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { router } from '@kit.ArkUI';
|
||||
import { promptAction } from '@kit.ArkUI';
|
||||
import { userAuth } from '@kit.UserAuthenticationKit';
|
||||
import { addAssetPromise, removeAssetPromise, queryAssetPromise, queryAuthAssetPromise, preQueryAssetPromise, log,
|
||||
postQueryAssetPromise } from '../model/AssetModel';
|
||||
|
||||
interface AssetItem {
|
||||
alias: string;
|
||||
secret: string;
|
||||
dataLabel: string;
|
||||
}
|
||||
|
||||
function isReserveClickable(reserveAccount: string, reservePassword: string, reserveLabel: string): boolean {
|
||||
return reserveAccount !== '' && reservePassword !== '' && reserveLabel != '';
|
||||
}
|
||||
|
||||
async function getAuthTokenCallback(challenge: Uint8Array,
|
||||
callback: (isSuccess: boolean, challenge: Uint8Array) => void) {
|
||||
const authParam: userAuth.AuthParam = {
|
||||
challenge: challenge,
|
||||
authType: [userAuth.UserAuthType.PIN,userAuth.UserAuthType.FACE,userAuth.UserAuthType.FINGERPRINT],
|
||||
authTrustLevel: userAuth.AuthTrustLevel.ATL1,
|
||||
};
|
||||
const widgetParam: userAuth.WidgetParam = {
|
||||
title: '请输入锁屏密码',
|
||||
};
|
||||
try {
|
||||
let userAuthInstance = userAuth.getUserAuthInstance(authParam, widgetParam);
|
||||
userAuthInstance.on('result', {
|
||||
onResult(result) {
|
||||
console.log('userAuthInstance callback result = ' + JSON.stringify(result));
|
||||
if (result.result == 12500000) {
|
||||
console.log('userAuthInstance callback result success');
|
||||
callback(true, result.token)
|
||||
} else if (result.result == 12500010) {
|
||||
promptAction.showToast({ message: $r('app.string.please_set_pwd') })
|
||||
callback(false, new Uint8Array(0))
|
||||
}
|
||||
}
|
||||
});
|
||||
userAuthInstance.start();
|
||||
} catch (error) {
|
||||
console.log('auth catch error: ' + JSON.stringify(error));
|
||||
promptAction.showToast({ message: $r('app.string.auth_failed') })
|
||||
callback(false, new Uint8Array(0))
|
||||
}
|
||||
}
|
||||
|
||||
function convertMapArrayToMapItem(array: Array<Map<string, string>>): Array<AssetItem>
|
||||
{
|
||||
let res = new Array<AssetItem>();
|
||||
for (let dataElement of array) {
|
||||
let tmp: AssetItem = {
|
||||
alias: dataElement.get('alias') as string,
|
||||
secret: dataElement.get('secret') as string,
|
||||
dataLabel: dataElement.get('label') as string,
|
||||
};
|
||||
res.push(tmp)
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct Page {
|
||||
private challenge: Uint8Array = new Uint8Array;
|
||||
private authToken: Uint8Array = new Uint8Array;
|
||||
@State reserveAccount: string = '';
|
||||
@State reservePassword: string = '';
|
||||
@State reserveLabel: string = '';
|
||||
@State deleteAccount: string = '';
|
||||
@State deleteLabel: string = '';
|
||||
@State checkAccount: string = '';
|
||||
@State checkLabel: string = '';
|
||||
@State eventType: string = ''
|
||||
@State index: number = 0
|
||||
@State assetArr: string[] = new Array<string>();
|
||||
private tabsController: TabsController = new TabsController();
|
||||
@State view: Visibility[] = [Visibility.Hidden, Visibility.Visible, Visibility.None];
|
||||
@State indexView: number = 0
|
||||
|
||||
@Builder TabBuilder(index: number, name: string) {
|
||||
Column() {
|
||||
Row().height(this.index === index ? 8 : 17)
|
||||
Text(name)
|
||||
.fontColor(0x182413)
|
||||
.fontSize(this.index === index ? 30 : 20)
|
||||
.fontWeight(this.index === index ? 700 : 500)
|
||||
.lineHeight(this.index === index ? 41 : 28)
|
||||
.opacity(this.index === index ? 1 : 0.7)
|
||||
.fontFamily(this.index === index ? 'HarmonyHeiTi-Bold' : 'HarmonyHeiTi-Medium')
|
||||
.margin(this.index == 0 ? {left: 24} : {left: 0})
|
||||
Row().height(this.index === index ? 7 : 11)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
|
||||
build() {
|
||||
Tabs({
|
||||
index: 0,
|
||||
controller: this.tabsController }) {
|
||||
/* 保存页面 */
|
||||
TabContent() {
|
||||
Column() {
|
||||
Column() {
|
||||
/* 账号 */
|
||||
Row() {
|
||||
Text("*").fontColor(0xFFE84026)
|
||||
Text($r('app.string.account'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(500)
|
||||
.margin({ top: "2.3%", bottom: "1.1%" })
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
.margin({ top: 4 })
|
||||
|
||||
/* 账号输入 */
|
||||
Row() {
|
||||
TextInput({ placeholder: $r('app.string.please_input_account') })
|
||||
.fontColor(0x182431)
|
||||
.defaultFocus(false)
|
||||
.padding({ top: '1.70%', right: '48.00px', bottom: '1.70%', left: '0.00px' })
|
||||
.backgroundColor(Color.Transparent)
|
||||
.borderRadius(0)
|
||||
.placeholderFont({ size: 16, weight: 400, family: 'HarmonyHeiTi', style: FontStyle.Normal })
|
||||
.onChange((value: string) => {
|
||||
this.reserveAccount = value;
|
||||
})
|
||||
.onEditChange((isEditing: boolean) => {
|
||||
if (isEditing === true) {
|
||||
this.eventType = 'Down1';
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
|
||||
if (this.eventType === 'Down1') {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: 12,
|
||||
right: 12
|
||||
})
|
||||
.backgroundColor(0x182431)
|
||||
} else {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431')
|
||||
}
|
||||
|
||||
/* 密码 */
|
||||
Row() {
|
||||
Text("*").fontColor(0xFFE84026)
|
||||
Text($r('app.string.secret_or_card_num'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.fontWeight(500)
|
||||
.margin({ top: "2.3%", bottom: "1.1%" })
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
|
||||
/* 密码输入 */
|
||||
Row() {
|
||||
TextInput({ placeholder: $r('app.string.please_input_secret_or_card_num') })
|
||||
.type(InputType.Password)
|
||||
.defaultFocus(false)
|
||||
.fontColor(0x182431)
|
||||
.padding({ top: '1.70%', right: '0', bottom: '1.70%', left: '0.00px' })
|
||||
.backgroundColor(Color.Transparent)
|
||||
.placeholderFont({ size: 16, weight: 400, family: 'HarmonyHeiTi', style: FontStyle.Normal })
|
||||
.onChange((value: string) => {
|
||||
this.reservePassword = value;
|
||||
})
|
||||
.onTouch((event: TouchEvent) => {
|
||||
if (event.type === TouchType.Down) {
|
||||
this.eventType = 'Down2';
|
||||
}
|
||||
})
|
||||
.margin({ top: '0.00vp', right: '-12vp', bottom: '4.00vp', left: '0.00vp' })
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
if (this.eventType === 'Down2') {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor(0x182431)
|
||||
} else {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431')
|
||||
}
|
||||
|
||||
/* 标签 */
|
||||
Row() {
|
||||
Text("*").fontColor(0xFFE84026)
|
||||
Text($r('app.string.label'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.fontWeight(500)
|
||||
.margin({ top: "2.3%", bottom: "1.1%" })
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
|
||||
/* 标签输入 */
|
||||
Row() {
|
||||
TextInput({ placeholder: $r('app.string.please_input_label') })
|
||||
.fontColor(0x182431)
|
||||
.defaultFocus(false)
|
||||
.padding({ top: '1.70%', right: '48.00px', bottom: '1.70%', left: '0.00px' })
|
||||
.backgroundColor(Color.Transparent)
|
||||
.placeholderFont({ size: 16, weight: 400, family: 'HarmonyHeiTi', style: FontStyle.Normal })
|
||||
.onChange((value: string) => {
|
||||
this.reserveLabel = value;
|
||||
})
|
||||
.onTouch((event: TouchEvent) => {
|
||||
if (event.type === TouchType.Down) {
|
||||
this.eventType = 'Down3';
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
if (this.eventType === 'Down3') {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor(0x182431).margin({ bottom: 4})
|
||||
} else {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431').margin({ bottom: 4})
|
||||
}
|
||||
}
|
||||
.backgroundColor(0xFFFFFF).borderRadius(16)
|
||||
|
||||
Blank()
|
||||
|
||||
Row() {
|
||||
/* 底部按钮 */
|
||||
Button($r('app.string.save'), { type: ButtonType.Capsule, stateEffect: false })
|
||||
.backgroundColor(0x007DFF).fontColor('white')
|
||||
.borderRadius(20)
|
||||
.width('86.7%')
|
||||
.height(40)
|
||||
.enabled(isReserveClickable(this.reserveAccount, this.reservePassword, this.reserveLabel))
|
||||
.onClick(() => {
|
||||
addAssetPromise(this.reserveAccount, this.reservePassword, this.reserveLabel)
|
||||
})
|
||||
}
|
||||
.margin({ bottom: '8.1%' })
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
.tabBar(this.TabBuilder(0, "保存"))
|
||||
|
||||
/* 删除页面 */
|
||||
TabContent() {
|
||||
Column() {
|
||||
Column() {
|
||||
/* 账号 */
|
||||
Row() {
|
||||
Text($r('app.string.account'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(500)
|
||||
.margin({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
.margin({ top: 4 })
|
||||
|
||||
/* 用户名输入 */
|
||||
Row() {
|
||||
TextInput({ placeholder: $r('app.string.please_input_account') })
|
||||
.fontColor(0x182431)
|
||||
.defaultFocus(false)
|
||||
.padding({ top: '1.70%', right: '48.00px', bottom: '1.70%', left: '0' })
|
||||
.backgroundColor(Color.Transparent)
|
||||
.placeholderFont({ size: 16, weight: 400, family: 'HarmonyHeiTi', style: FontStyle.Normal })
|
||||
.onChange((value: string) => {
|
||||
this.deleteAccount = value;
|
||||
})
|
||||
.onTouch((event: TouchEvent) => {
|
||||
if (event.type === TouchType.Down) {
|
||||
this.eventType = 'Down4';
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
|
||||
if (this.eventType === 'Down4') {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor(0x182431)
|
||||
} else {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431')
|
||||
}
|
||||
|
||||
/* 标签 */
|
||||
Row() {
|
||||
Text($r('app.string.label'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.fontWeight(500)
|
||||
.margin({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
|
||||
/* 标签输入 */
|
||||
Row() {
|
||||
TextInput({ placeholder: $r('app.string.please_input_label') })
|
||||
.fontColor(0x182431)
|
||||
.defaultFocus(false)
|
||||
.padding({ top: '1.70%', right: '48.00px', bottom: '1.70%', left: '0' })
|
||||
.backgroundColor(Color.Transparent)
|
||||
.placeholderFont({ size: 16, weight: 400, family: 'HarmonyHeiTi', style: FontStyle.Normal })
|
||||
.onChange((value: string) => {
|
||||
this.deleteLabel = value;
|
||||
})
|
||||
.onTouch((event: TouchEvent) => {
|
||||
if (event.type === TouchType.Down) {
|
||||
this.eventType = 'Down5';
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
|
||||
if (this.eventType === 'Down5') {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor(0x182431).margin({ bottom: 4})
|
||||
} else {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431').margin({ bottom: 4})
|
||||
}
|
||||
}
|
||||
.backgroundColor(0xFFFFFF).borderRadius(16)
|
||||
|
||||
Blank()
|
||||
Row() {
|
||||
/* 底部按钮 */
|
||||
Button($r('app.string.delete'), { type: ButtonType.Capsule, stateEffect: false })
|
||||
.backgroundColor(0x007DFF).fontColor('white')
|
||||
.borderRadius(20)
|
||||
.width('86.7%')
|
||||
.height(40)
|
||||
.onClick(() => {
|
||||
removeAssetPromise(this.deleteAccount, this.deleteLabel)
|
||||
})
|
||||
}
|
||||
.margin({ bottom: '8.1%' })
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
.tabBar(this.TabBuilder(1, "删除"))
|
||||
|
||||
/* 更新页面 */
|
||||
TabContent() {
|
||||
Column() {
|
||||
Column() {
|
||||
List({ space: 0, initialIndex: 0 }) { // 查询列表
|
||||
ForEach(this.assetArr, (item: string) => {
|
||||
ListItem() {
|
||||
Column() {
|
||||
/* 账号 */
|
||||
Row() {
|
||||
Row() {
|
||||
Text(item)
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(500)
|
||||
.textAlign(TextAlign.Start)
|
||||
.margin({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
|
||||
Blank()
|
||||
Row() {
|
||||
Image($r('app.media.forward'))
|
||||
.height(18)
|
||||
.width(9)
|
||||
.fillColor('#182431')
|
||||
}
|
||||
}
|
||||
.width('100%').height('7.14%')
|
||||
.onClick(async () => {
|
||||
let account = await queryAuthAssetPromise(item, this.challenge, this.authToken);
|
||||
router.pushUrl({
|
||||
url: 'pages/UpdatePage',
|
||||
params: { name: item, pwd: account.get('secret'), label: account.get("label") }
|
||||
}, router.RouterMode.Standard, (err) => {
|
||||
if (err) {
|
||||
console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
.margin({ right: 12, left: 12 })
|
||||
}
|
||||
}, (item: string) => item)
|
||||
}
|
||||
.listDirection(Axis.Vertical) // 排列方向
|
||||
.divider({ strokeWidth: 1, color: '#0D182431', startMargin: 12, endMargin: 12 }) // 每行之间的分界线
|
||||
.edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果
|
||||
}
|
||||
.margin({ right: 12, left: 12 })
|
||||
.backgroundColor(0xFFFFFF).borderRadius(16)
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
.tabBar(this.TabBuilder(2, "更新"))
|
||||
|
||||
/* 查询页面 */
|
||||
TabContent() {
|
||||
Column() {
|
||||
Column() {
|
||||
/* 账号 */
|
||||
Row() {
|
||||
Text($r('app.string.account'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(500)
|
||||
.textAlign(TextAlign.Start)
|
||||
.margin({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
.margin({ top: 4 })
|
||||
|
||||
/* 用户名输入 */
|
||||
Row() {
|
||||
TextInput({ placeholder: $r('app.string.please_input_account') })
|
||||
.fontColor(0x182431)
|
||||
.defaultFocus(false)
|
||||
.padding({ top: '1.70%', right: '48.00px', bottom: '1.70%', left: '0' })
|
||||
.backgroundColor(Color.Transparent)
|
||||
.placeholderFont({ size: 16, weight: 400, family: 'HarmonyHeiTi', style: FontStyle.Normal })
|
||||
.onChange((value: string) => {
|
||||
this.checkAccount = value;
|
||||
})
|
||||
.onTouch((event: TouchEvent) => {
|
||||
if (event.type === TouchType.Down) {
|
||||
this.eventType = 'Down6';
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
|
||||
if (this.eventType === 'Down6') {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor(0x182431)
|
||||
} else {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431')
|
||||
}
|
||||
|
||||
/* 标签 */
|
||||
Row() {
|
||||
Text($r('app.string.label'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(500)
|
||||
.textAlign(TextAlign.Start)
|
||||
.margin({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
|
||||
/* 标签输入 */
|
||||
Row() {
|
||||
TextInput({ placeholder: $r('app.string.please_input_label') })
|
||||
.fontColor(0x182431)
|
||||
.defaultFocus(false)
|
||||
.padding({ top: '1.70%', right: '48.00px', bottom: '1.70%', left: '0' })
|
||||
.backgroundColor(Color.Transparent)
|
||||
.placeholderFont({ size: 16, weight: 400, family: 'HarmonyHeiTi', style: FontStyle.Normal })
|
||||
.onChange((value: string) => {
|
||||
this.checkLabel = value;
|
||||
})
|
||||
.onTouch((event: TouchEvent) => {
|
||||
if (event.type === TouchType.Down) {
|
||||
this.eventType = 'Down7';
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
|
||||
if (this.eventType === 'Down7') {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor(0x182431).margin({bottom: 4})
|
||||
} else {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431').margin({bottom: 4})
|
||||
}
|
||||
}
|
||||
.backgroundColor(0xFFFFFF).borderRadius(16)
|
||||
|
||||
Blank()
|
||||
Row() {
|
||||
/* 底部按钮 */
|
||||
Button($r('app.string.search'), { type: ButtonType.Capsule, stateEffect: false })
|
||||
.backgroundColor(0x007DFF)
|
||||
.borderRadius(20)
|
||||
.width('86.7%')
|
||||
.height(40)
|
||||
.onClick(async () => {
|
||||
// 需要执行的操作
|
||||
// 如果查询的时候输入了账号 则表示精确查询 进行二次访问控制
|
||||
if (this.checkAccount.length > 0) {
|
||||
let challenge = await preQueryAssetPromise(this.checkAccount);
|
||||
if (challenge.length == 0) {
|
||||
log("查询失败")
|
||||
return
|
||||
}
|
||||
this.challenge = challenge
|
||||
getAuthTokenCallback(this.challenge, async (isSuccess: boolean, authToken: Uint8Array) => {
|
||||
if (isSuccess) {
|
||||
console.log('get auth token success!')
|
||||
this.authToken = authToken
|
||||
|
||||
let account = await queryAuthAssetPromise(this.checkAccount, this.challenge, this.authToken);
|
||||
postQueryAssetPromise(this.challenge)
|
||||
this.challenge = new Uint8Array;
|
||||
this.authToken = new Uint8Array;
|
||||
router.pushUrl({
|
||||
url: 'pages/QueryResultPage',
|
||||
params: {
|
||||
data_array_map: convertMapArrayToMapItem(new Array<Map<string, string>>(account))
|
||||
}
|
||||
}, router.RouterMode.Standard, (err) => {
|
||||
if (err) {
|
||||
console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
let accountList = queryAssetPromise(this.checkAccount, this.checkLabel);
|
||||
accountList.then(data => {
|
||||
router.pushUrl({
|
||||
url: 'pages/QueryResultPage', // 目标url
|
||||
params: {
|
||||
data_array_map: convertMapArrayToMapItem(data)
|
||||
}
|
||||
}, router.RouterMode.Standard, (err) => {
|
||||
if (err) {
|
||||
console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);
|
||||
return;
|
||||
}
|
||||
console.info('Invoke pushUrl succeeded.');
|
||||
});
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ bottom: '8.1%' })
|
||||
}
|
||||
.height('100%')
|
||||
|
||||
}
|
||||
.tabBar(this.TabBuilder(3, "查询"))
|
||||
}
|
||||
.scrollable(true)
|
||||
.backgroundColor(0xf1f3f5)
|
||||
.barMode(BarMode.Fixed)
|
||||
.barHeight(56)
|
||||
.onChange(async (index: number) => {
|
||||
if (index == 2 && this.index != 2) {
|
||||
let challenge = await preQueryAssetPromise("");
|
||||
console.log('get challenge success!')
|
||||
this.challenge = challenge
|
||||
// get auth token
|
||||
getAuthTokenCallback(this.challenge, async (isSuccess: boolean, authToken: Uint8Array) => {
|
||||
if (isSuccess) {
|
||||
console.log('get auth token success!')
|
||||
this.authToken = authToken
|
||||
let resultList = await queryAssetPromise('', '');
|
||||
for (let accountListElement of resultList) {
|
||||
let str = accountListElement.get('alias');
|
||||
if (str !== undefined) {
|
||||
this.assetArr.push(str)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (this.challenge.length > 0) {
|
||||
postQueryAssetPromise(this.challenge)
|
||||
this.challenge = new Uint8Array;
|
||||
this.authToken = new Uint8Array;
|
||||
this.assetArr = new Array<string>();
|
||||
}
|
||||
this.index = index;
|
||||
})
|
||||
}
|
||||
}
|
182
code/BasicFeature/Security/Asset/entry/src/main/ets/pages/QueryResultPage.ets
Executable file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { router } from '@kit.ArkUI';
|
||||
|
||||
interface AssetItem {
|
||||
alias: string;
|
||||
secret: string;
|
||||
dataLabel: string;
|
||||
}
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct QueryResultPage {
|
||||
@State param: Record<string, Array<AssetItem>> = router.getParams() as Record<string, Array<AssetItem>>;
|
||||
@State data: Array<AssetItem> = this.param.data_array_map as Array<AssetItem>;
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Row() {
|
||||
Image($r('app.media.back'))
|
||||
.height(18)
|
||||
.width(20)
|
||||
.onClick(() => {
|
||||
// 返回到上一页面,相当于pop操作
|
||||
router.back();
|
||||
})
|
||||
|
||||
Text($r('app.string.search_result'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(20)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(28)
|
||||
.fontWeight(700)
|
||||
.margin({ left: '5%' })
|
||||
.textAlign(TextAlign.Center)
|
||||
}
|
||||
.width('86.7%').height(56)
|
||||
|
||||
Column() {
|
||||
List({ space: 0, initialIndex: 0 }) {
|
||||
ForEach(this.data, (item: AssetItem) => {
|
||||
ListItem() {
|
||||
Column() {
|
||||
Row() {
|
||||
Row() {
|
||||
Text($r('app.string.account'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(500)
|
||||
.margin({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
Blank()
|
||||
Row() {
|
||||
Text(item.alias.toString())
|
||||
.opacity(0.6)
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(19)
|
||||
.fontWeight(400)
|
||||
.baselineOffset(0)
|
||||
.margin({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
}
|
||||
.width('86.7%').height('7.14%')
|
||||
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431')
|
||||
|
||||
/* 密码/信用卡号 */
|
||||
if (item.secret) {
|
||||
Row() {
|
||||
Row() {
|
||||
Text($r('app.string.secret_or_card_num'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(500)
|
||||
.textAlign(TextAlign.Start)
|
||||
.padding({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
|
||||
Blank()
|
||||
Row() {
|
||||
Text(item.secret.toString())
|
||||
.opacity(0.6)
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(19)
|
||||
.fontWeight(400)
|
||||
.textAlign(TextAlign.End)
|
||||
.padding({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
}.width('86.7%').height('6.7%')
|
||||
}
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431')
|
||||
/* 标签 */
|
||||
Row() {
|
||||
Row() {
|
||||
Text($r('app.string.label2'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(500)
|
||||
.baselineOffset(0)
|
||||
.textAlign(TextAlign.Start)
|
||||
.padding({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
|
||||
Blank()
|
||||
Row() {
|
||||
Text(item.dataLabel.toString())
|
||||
.opacity(0.6)
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(19)
|
||||
.fontWeight(400)
|
||||
.baselineOffset(0)
|
||||
.textAlign(TextAlign.End)
|
||||
.padding({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
}.width('86.7%').height('7.14%')
|
||||
}
|
||||
.margin({ left: 12, right: -12, bottom: 12 })
|
||||
.backgroundColor(0xFFFFFF).borderRadius(16)
|
||||
}
|
||||
}, (item: AssetItem) => JSON.stringify(item))
|
||||
}
|
||||
.listDirection(Axis.Vertical) // 排列方向
|
||||
.edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果
|
||||
}
|
||||
}
|
||||
.width("100%").height("100%").backgroundColor(0xf1f3f5)
|
||||
}
|
||||
|
||||
pageTransition() {
|
||||
// 定义页面进入时的效果,从右侧滑入,时长为1000ms,页面栈发生push操作时该效果才生效
|
||||
PageTransitionEnter({ type: RouteType.Push, duration: 300 })
|
||||
.slide(SlideEffect.Right)
|
||||
// 定义页面进入时的效果,从左侧滑入,时长为1000ms,页面栈发生pop操作时该效果才生效
|
||||
PageTransitionEnter({ type: RouteType.Pop, duration: 300 })
|
||||
.slide(SlideEffect.Left)
|
||||
// 定义页面退出时的效果,向左侧滑出,时长为1000ms,页面栈发生push操作时该效果才生效
|
||||
PageTransitionExit({ type: RouteType.Push, duration: 300 })
|
||||
.slide(SlideEffect.Left)
|
||||
// 定义页面退出时的效果,向右侧滑出,时长为1000ms,页面栈发生pop操作时该效果才生效
|
||||
PageTransitionExit({ type: RouteType.Pop, duration: 300 })
|
||||
.slide(SlideEffect.Right)
|
||||
}
|
||||
}
|
218
code/BasicFeature/Security/Asset/entry/src/main/ets/pages/UpdatePage.ets
Executable file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { router } from '@kit.ArkUI';
|
||||
import { updateAssetPromise } from '../model/AssetModel';
|
||||
|
||||
function isUpdateClickable(reservePassword: string): boolean {
|
||||
return reservePassword !== '';
|
||||
}
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct UpdatePage {
|
||||
@State params: Record<string, string> = router.getParams() as Record<string, string>;
|
||||
@State user: string = this.params.name as string;
|
||||
@State pwd: string = this.params.pwd as string;
|
||||
@State label: string = this.params.label as string;
|
||||
@State reservePassword: string = this.pwd;
|
||||
@State reserveLabel: string = this.label;
|
||||
@State eventType: string = ''
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Row() {
|
||||
Image($r('app.media.back'))
|
||||
.height(18)
|
||||
.width(20)
|
||||
.onClick(() => {
|
||||
// 返回到上一页面,相当于pop操作
|
||||
router.back();
|
||||
})
|
||||
Text($r('app.string.update'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(20)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(28)
|
||||
.fontWeight(700)
|
||||
.margin({ left: '5%' })
|
||||
.textAlign(TextAlign.Center)
|
||||
}.width('86.7%').height(56)
|
||||
|
||||
Column() {
|
||||
/* 账号 */
|
||||
Row() {
|
||||
Text($r('app.string.account'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(500)
|
||||
.textAlign(TextAlign.Start)
|
||||
.padding({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
.width('86.7%').height('6.7%')
|
||||
|
||||
/* 用户名输入 */
|
||||
Row() {
|
||||
Text(this.user)
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.opacity(0.6)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(400)
|
||||
.textAlign(TextAlign.Start)
|
||||
.padding({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
.width('86.7%').height('6.7%')
|
||||
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431')
|
||||
|
||||
/* 密码 */
|
||||
Row() {
|
||||
Text("*").fontColor(0xFFE84026)
|
||||
Text($r('app.string.secret_or_card_num'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(500)
|
||||
.padding({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
.width('86.7%').height('6.7%')
|
||||
|
||||
/* 密码输入 */
|
||||
Row() {
|
||||
TextInput({ text: this.pwd })
|
||||
.type(InputType.Password)
|
||||
.defaultFocus(false)
|
||||
.fontColor(0x182431)
|
||||
.padding({ top: '1.70%', right: '48.00px', bottom: '1.70%', left: '0' })
|
||||
.backgroundColor(Color.Transparent)
|
||||
.placeholderFont({ size: 16, weight: 400, family: 'HarmonyHeiTi', style: FontStyle.Normal })
|
||||
.onChange((value: string) => {
|
||||
this.reservePassword = value;
|
||||
})
|
||||
.onTouch((event: TouchEvent) => {
|
||||
if (event.type === TouchType.Down) {
|
||||
this.eventType = 'Down9';
|
||||
}
|
||||
})
|
||||
.margin({ right: -12 })
|
||||
}
|
||||
.width('86.7%').height('6.7%')
|
||||
|
||||
if (this.eventType === 'Down9') {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor(0x182431)
|
||||
} else {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431')
|
||||
}
|
||||
|
||||
/* 标签 */
|
||||
Row() {
|
||||
Text($r('app.string.label'))
|
||||
.fontFamily("HarmonyHeiTi")
|
||||
.fontSize(16)
|
||||
.fontColor(0x182431)
|
||||
.lineHeight(22)
|
||||
.fontWeight(500)
|
||||
.baselineOffset(0)
|
||||
.textAlign(TextAlign.Start)
|
||||
.padding({ top: '2.3%', bottom: '1.1%' })
|
||||
}
|
||||
.width('86.7%').height('6.7%')
|
||||
|
||||
/* 标签输入 */
|
||||
Row() {
|
||||
TextInput({ text: this.label })
|
||||
.defaultFocus(false)
|
||||
.fontColor(0x182431)
|
||||
.padding({ top: '1.70%', right: '48.00px', bottom: '1.70%', left: '0' })
|
||||
.backgroundColor(Color.Transparent)
|
||||
.placeholderFont({ size: 16, weight: 400, family: 'HarmonyHeiTi', style: FontStyle.Normal })
|
||||
.onChange((value: string) => {
|
||||
this.reserveLabel = value;
|
||||
})
|
||||
.onTouch((event: TouchEvent) => {
|
||||
if (event.type === TouchType.Down) {
|
||||
this.eventType = 'Down10';
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('86.7%').height('6.7%')
|
||||
|
||||
if (this.eventType === 'Down10') {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor(0x182431).margin({ bottom: 4 })
|
||||
} else {
|
||||
Line()
|
||||
.width('86.7%')
|
||||
.height('0.5vp')
|
||||
.margin({
|
||||
left: '12vp',
|
||||
right: '12vp'
|
||||
})
|
||||
.backgroundColor('#0D182431').margin({ bottom: 4 })
|
||||
}
|
||||
}
|
||||
.backgroundColor(0xFFFFFF).borderRadius(16)
|
||||
|
||||
Blank()
|
||||
Row() {
|
||||
/* 底部按钮 */
|
||||
Button($r('app.string.update'), { type: ButtonType.Capsule, stateEffect: false })
|
||||
.backgroundColor(0x007DFF).fontColor('white')
|
||||
.borderRadius(20)
|
||||
.width('86.7%')
|
||||
.height(40)
|
||||
.enabled(isUpdateClickable(this.reservePassword))
|
||||
.onClick(() => {
|
||||
updateAssetPromise(this.user, this.reservePassword, this.reserveLabel)
|
||||
})
|
||||
}
|
||||
.margin({ bottom: '8.1%' })
|
||||
}
|
||||
// .margin({ right: 12, left: 12 })
|
||||
.width("100%").height('100%').backgroundColor(0xf1f3f5)
|
||||
}
|
||||
}
|
60
code/BasicFeature/Security/Asset/entry/src/main/module.json5
Executable file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
{
|
||||
"module": {
|
||||
"name": "entry",
|
||||
"type": "entry",
|
||||
"description": "$string:module_desc",
|
||||
"mainElement": "EntryAbility",
|
||||
"deviceTypes": [
|
||||
"default",
|
||||
"tablet"
|
||||
],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false,
|
||||
"pages": "$profile:main_pages",
|
||||
"abilities": [
|
||||
{
|
||||
"name": "EntryAbility",
|
||||
"srcEntry": "./ets/entryability/EntryAbility.ts",
|
||||
"description": "$string:EntryAbility_desc",
|
||||
"icon": "$media:app_icon",
|
||||
"label": "$string:EntryAbility_label",
|
||||
"startWindowIcon": "$media:app_icon",
|
||||
"startWindowBackground": "$color:start_window_background",
|
||||
"exported": true,
|
||||
"skills": [
|
||||
{
|
||||
"entities": [
|
||||
"entity.system.home"
|
||||
],
|
||||
"actions": [
|
||||
"action.system.home"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"requestPermissions": [
|
||||
{
|
||||
"name": "ohos.permission.ACCESS_BIOMETRIC"
|
||||
},
|
||||
{
|
||||
"name": "ohos.permission.STORE_PERSISTENT_DATA"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
{
|
||||
"color": [
|
||||
{
|
||||
"name": "start_window_background",
|
||||
"value": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"name": "column_background_color",
|
||||
"value": "#F5F5F5"
|
||||
},
|
||||
{
|
||||
"name": "custom_color",
|
||||
"value": "#182431"
|
||||
},
|
||||
{
|
||||
"name": "custom_button_color",
|
||||
"value": "#007DFF"
|
||||
},
|
||||
{
|
||||
"name": "custom_blank_color",
|
||||
"value": "#F2F2F2"
|
||||
},
|
||||
{
|
||||
"name": "place_color",
|
||||
"value": "#99000000"
|
||||
},
|
||||
{
|
||||
"name": "divider_color",
|
||||
"value": "#0D182431"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
{
|
||||
"float": [
|
||||
{
|
||||
"name": "image_back_size",
|
||||
"value": "26vp"
|
||||
},
|
||||
{
|
||||
"name": "avatar_size",
|
||||
"value": "56vp"
|
||||
},
|
||||
{
|
||||
"name": "personal_font_size",
|
||||
"value": "16fp"
|
||||
},
|
||||
{
|
||||
"name": "title_hobbies_size",
|
||||
"value": "20fp"
|
||||
},
|
||||
{
|
||||
"name": "title_line_height",
|
||||
"value": "28vp"
|
||||
},
|
||||
{
|
||||
"name": "label_size",
|
||||
"value": "16fp"
|
||||
},
|
||||
{
|
||||
"name": "options_height",
|
||||
"value": "22vp"
|
||||
},
|
||||
{
|
||||
"name": "toggle_size",
|
||||
"value": "20vp"
|
||||
},
|
||||
{
|
||||
"name": "options_top_distance",
|
||||
"value": "13vp"
|
||||
},
|
||||
{
|
||||
"name": "options_bottom_distance",
|
||||
"value": "13vp"
|
||||
},
|
||||
{
|
||||
"name": "divider_height",
|
||||
"value": "0.5vp"
|
||||
},
|
||||
{
|
||||
"name": "list_top_distance",
|
||||
"value": "14vp"
|
||||
},
|
||||
{
|
||||
"name": "list_bottom_distance",
|
||||
"value": "8vp"
|
||||
},
|
||||
{
|
||||
"name": "options_list_height",
|
||||
"value": "242vp"
|
||||
},
|
||||
{
|
||||
"name": "blank_width",
|
||||
"value": "1vp"
|
||||
},
|
||||
{
|
||||
"name": "blank_opacity",
|
||||
"value": "1vp"
|
||||
},
|
||||
{
|
||||
"name": "blank_height",
|
||||
"value": "25vp"
|
||||
},
|
||||
{
|
||||
"name": "dialog_radius",
|
||||
"value": "32vp"
|
||||
},
|
||||
{
|
||||
"name": "title_left_distance",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "label_left_distance",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "dialog_left_distance",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "dialog_top_distance",
|
||||
"value": "14vp"
|
||||
},
|
||||
{
|
||||
"name": "toggle_right_distance",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "dialog_bottom_distance",
|
||||
"value": "16vp"
|
||||
},
|
||||
{
|
||||
"name": "button_text_size",
|
||||
"value": "16fp"
|
||||
},
|
||||
{
|
||||
"name": "button_height",
|
||||
"value": "40vp"
|
||||
},
|
||||
{
|
||||
"name": "text_image_size",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "image_left_distance",
|
||||
"value": "12vp"
|
||||
},
|
||||
{
|
||||
"name": "text_size",
|
||||
"value": "16vp"
|
||||
},
|
||||
{
|
||||
"name": "content_left_distance",
|
||||
"value": "16vp"
|
||||
},
|
||||
{
|
||||
"name": "content_right_distance",
|
||||
"value": "7vp"
|
||||
},
|
||||
{
|
||||
"name": "arrow_image_width",
|
||||
"value": "12vp"
|
||||
},
|
||||
{
|
||||
"name": "arrow_image_height",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "arrow_right_distance",
|
||||
"value": "14vp"
|
||||
},
|
||||
{
|
||||
"name": "row_top_distance",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "row_radius",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "row_height",
|
||||
"value": "64vp"
|
||||
},
|
||||
{
|
||||
"name": "input_image_size",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "input_image_left",
|
||||
"value": "12vp"
|
||||
},
|
||||
{
|
||||
"name": "input_text_size",
|
||||
"value": "16fp"
|
||||
},
|
||||
{
|
||||
"name": "input_left_inside",
|
||||
"value": "12vp"
|
||||
},
|
||||
{
|
||||
"name": "input_right_inside",
|
||||
"value": "32vp"
|
||||
},
|
||||
{
|
||||
"name": "text_input_height",
|
||||
"value": "48vp"
|
||||
},
|
||||
{
|
||||
"name": "input_row_top",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "input_row_radius",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "input_row_height",
|
||||
"value": "64vp"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"boolean": [
|
||||
{
|
||||
"name": "boolean_1",
|
||||
"value": true
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_desc",
|
||||
"value": "module description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "Main program entry"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_label",
|
||||
"value": "MultipleWindow"
|
||||
},
|
||||
{
|
||||
"name": "please_set_pwd",
|
||||
"value": "please set screen password"
|
||||
},
|
||||
{
|
||||
"name": "auth_failed",
|
||||
"value": "auth failed"
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"value": "account"
|
||||
},
|
||||
{
|
||||
"name": "please_input_account",
|
||||
"value": "please input account"
|
||||
},
|
||||
{
|
||||
"name": "secret_or_card_num",
|
||||
"value": "secret or card number"
|
||||
},
|
||||
{
|
||||
"name": "please_input_secret_or_card_num",
|
||||
"value": "please input secret or card number"
|
||||
},
|
||||
{
|
||||
"name": "label",
|
||||
"value": "label(max 4, split by ;)"
|
||||
},
|
||||
{
|
||||
"name": "label2",
|
||||
"value": "label"
|
||||
},
|
||||
{
|
||||
"name": "please_input_label",
|
||||
"value": "please input label"
|
||||
},
|
||||
{
|
||||
"name": "save",
|
||||
"value": "save"
|
||||
},
|
||||
{
|
||||
"name": "delete",
|
||||
"value": "delete"
|
||||
},
|
||||
{
|
||||
"name": "search",
|
||||
"value": "search"
|
||||
},
|
||||
{
|
||||
"name": "search_result",
|
||||
"value": "search result"
|
||||
},
|
||||
{
|
||||
"name": "update",
|
||||
"value": "update"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
{
|
||||
"strarray": [
|
||||
{
|
||||
"name": "sex_array",
|
||||
"value": [
|
||||
{
|
||||
"value": "male"
|
||||
},
|
||||
{
|
||||
"value": "female"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hobbies_data",
|
||||
"value": [
|
||||
{
|
||||
"value": "Soccer"
|
||||
},
|
||||
{
|
||||
"value": "Badminton"
|
||||
},
|
||||
{
|
||||
"value": "Travelling"
|
||||
},
|
||||
{
|
||||
"value": "Playing games"
|
||||
},
|
||||
{
|
||||
"value": "Reading books"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"src": [
|
||||
"pages/Index",
|
||||
"pages/QueryResultPage",
|
||||
"pages/UpdatePage"
|
||||
]
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_desc",
|
||||
"value": "module description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_label",
|
||||
"value": "label"
|
||||
},
|
||||
{
|
||||
"name": "please_set_pwd",
|
||||
"value": "please set screen password"
|
||||
},
|
||||
{
|
||||
"name": "auth_failed",
|
||||
"value": "auth failed"
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"value": "account"
|
||||
},
|
||||
{
|
||||
"name": "please_input_account",
|
||||
"value": "please input account"
|
||||
},
|
||||
{
|
||||
"name": "secret_or_card_num",
|
||||
"value": "secret or card number"
|
||||
},
|
||||
{
|
||||
"name": "please_input_secret_or_card_num",
|
||||
"value": "please input secret or card number"
|
||||
},
|
||||
{
|
||||
"name": "label",
|
||||
"value": "label(max 4, split by ;)"
|
||||
},
|
||||
{
|
||||
"name": "label2",
|
||||
"value": "label"
|
||||
},
|
||||
{
|
||||
"name": "please_input_label",
|
||||
"value": "please input label"
|
||||
},
|
||||
{
|
||||
"name": "save",
|
||||
"value": "save"
|
||||
},
|
||||
{
|
||||
"name": "delete",
|
||||
"value": "delete"
|
||||
},
|
||||
{
|
||||
"name": "search",
|
||||
"value": "search"
|
||||
},
|
||||
{
|
||||
"name": "search_result",
|
||||
"value": "search result"
|
||||
},
|
||||
{
|
||||
"name": "update",
|
||||
"value": "update"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_desc",
|
||||
"value": "模块描述"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_label",
|
||||
"value": "label"
|
||||
},
|
||||
{
|
||||
"name": "please_set_pwd",
|
||||
"value": "请设置锁屏密码"
|
||||
},
|
||||
{
|
||||
"name": "auth_failed",
|
||||
"value": "认证失败"
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"value": "账号"
|
||||
},
|
||||
{
|
||||
"name": "please_input_account",
|
||||
"value": "请输入账号"
|
||||
},
|
||||
{
|
||||
"name": "secret_or_card_num",
|
||||
"value": "密码/信用卡号"
|
||||
},
|
||||
{
|
||||
"name": "please_input_secret_or_card_num",
|
||||
"value": "请输入密码/信用卡号"
|
||||
},
|
||||
{
|
||||
"name": "label",
|
||||
"value": "标签(最多4个,以;分隔)"
|
||||
},
|
||||
{
|
||||
"name": "label2",
|
||||
"value": "标签"
|
||||
},
|
||||
{
|
||||
"name": "please_input_label",
|
||||
"value": "请输入标签名称"
|
||||
},
|
||||
{
|
||||
"name": "save",
|
||||
"value": "保存"
|
||||
},
|
||||
{
|
||||
"name": "delete",
|
||||
"value": "删除"
|
||||
},
|
||||
{
|
||||
"name": "search",
|
||||
"value": "查询"
|
||||
},
|
||||
{
|
||||
"name": "search_result",
|
||||
"value": "查询结果"
|
||||
},
|
||||
{
|
||||
"name": "update",
|
||||
"value": "更新"
|
||||
}
|
||||
]
|
||||
}
|
126
code/BasicFeature/Security/Asset/entry/src/ohosTest/ets/test/Ability.test.ets
Executable file
@ -0,0 +1,126 @@
|
||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
|
||||
import { addAssetPromise,
|
||||
postQueryAssetPromise,
|
||||
preQueryAssetPromise,
|
||||
queryAssetPromise,
|
||||
removeAssetPromise,
|
||||
updateAssetPromise } from '../../../main/ets/model/AssetModel';
|
||||
|
||||
export default function abilityTest() {
|
||||
describe('ActsAbilityTest', () => {
|
||||
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
|
||||
beforeAll(() => {
|
||||
// Presets an action, which is performed only once before all test cases of the test suite start.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
beforeEach(() => {
|
||||
// Presets an action, which is performed before each unit test case starts.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
afterEach(() => {
|
||||
// Presets a clear action, which is performed after each unit test case ends.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
afterAll(() => {
|
||||
// Presets a clear action, which is performed after all test cases of the test suite end.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
it('assertContain', 0, () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
|
||||
let a = 'abc';
|
||||
let b = 'b';
|
||||
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
|
||||
expect(a).assertContain(b);
|
||||
expect(a).assertEqual(a);
|
||||
})
|
||||
it('assertAdd', 0, async () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
|
||||
let account = 'asset_account';
|
||||
let pwd = 'pwd';
|
||||
let label ='label1;label2';
|
||||
try {
|
||||
await addAssetPromise(account, pwd, label);
|
||||
let delete_label = 'label1';
|
||||
await removeAssetPromise(account, delete_label);
|
||||
expect(0).assertEqual(0);
|
||||
} catch (error) {
|
||||
expect(0).assertEqual(false);
|
||||
}
|
||||
})
|
||||
|
||||
it('assertQuery', 0, async () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
|
||||
let account = 'asset_account';
|
||||
let pwd = 'pwd';
|
||||
let label ='label1;label2';
|
||||
try {
|
||||
await addAssetPromise(account, pwd, label);
|
||||
let query_label = 'label1';
|
||||
await queryAssetPromise(account, query_label);
|
||||
let delete_label = 'label1';
|
||||
await removeAssetPromise(account, delete_label);
|
||||
expect(0).assertEqual(0);
|
||||
} catch (error) {
|
||||
expect(0).assertEqual(false);
|
||||
}
|
||||
})
|
||||
|
||||
it('assertUpdate', 0, async () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
|
||||
let account = 'asset_account';
|
||||
let pwd = 'pwd';
|
||||
let label ='label1;label2';
|
||||
try {
|
||||
await addAssetPromise(account, pwd, label);
|
||||
let reserve_label = 'label1';
|
||||
let reserve_password = '123';
|
||||
await updateAssetPromise(account, reserve_password, reserve_label);
|
||||
let delete_label = 'label1';
|
||||
await removeAssetPromise(account, delete_label);
|
||||
expect(0).assertEqual(0);
|
||||
} catch (error) {
|
||||
expect(0).assertEqual(false);
|
||||
}
|
||||
})
|
||||
|
||||
it('assertDelete', 0, async () => {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
|
||||
let account = 'asset_account';
|
||||
let pwd = 'pwd';
|
||||
let label ='label1;label2';
|
||||
try {
|
||||
await addAssetPromise(account, pwd, label);
|
||||
let delete_label = 'label1';
|
||||
await removeAssetPromise(account, delete_label);
|
||||
expect(0).assertEqual(0);
|
||||
} catch (error) {
|
||||
expect(0).assertEqual(false);
|
||||
}
|
||||
})
|
||||
|
||||
it('assertPreQuery', 0, async () => {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
|
||||
let account = 'asset_account';
|
||||
let pwd = 'pwd';
|
||||
let label ='label1;label2';
|
||||
try {
|
||||
await addAssetPromise(account, pwd, label);
|
||||
let challenge = await preQueryAssetPromise(account);
|
||||
await postQueryAssetPromise(challenge);
|
||||
let delete_label = 'label1';
|
||||
await removeAssetPromise(account, delete_label);
|
||||
expect(0).assertEqual(0);
|
||||
} catch (error) {
|
||||
expect(0).assertEqual(false);
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
import abilityTest from './Ability.test';
|
||||
|
||||
export default function testsuite() {
|
||||
abilityTest();
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
|
||||
import { abilityDelegatorRegistry } from '@kit.TestKit';
|
||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||
import { window } from '@kit.ArkUI';
|
||||
import { Hypium } from '@ohos/hypium';
|
||||
import testsuite from '../test/List.test';
|
||||
|
||||
export default class TestAbility extends UIAbility {
|
||||
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');
|
||||
let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator;
|
||||
abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator();
|
||||
let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs;
|
||||
abilityDelegatorArguments = abilityDelegatorRegistry.getArguments();
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
|
||||
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
|
||||
}
|
||||
|
||||
onWindowStageCreate(windowStage: window.WindowStage) {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
|
||||
windowStage.loadContent('testability/pages/Index', (err) => {
|
||||
if (err.code) {
|
||||
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
|
||||
return;
|
||||
}
|
||||
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
|
||||
});
|
||||
}
|
||||
|
||||
onWindowStageDestroy() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
|
||||
}
|
||||
|
||||
onForeground() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
|
||||
}
|
||||
|
||||
onBackground() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
@Entry
|
||||
@Component
|
||||
struct Index {
|
||||
@State message: string = 'Hello World';
|
||||
|
||||
build() {
|
||||
Row() {
|
||||
Column() {
|
||||
Text(this.message)
|
||||
.fontSize(50)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
import { abilityDelegatorRegistry, TestRunner } from '@kit.TestKit';
|
||||
import { UIAbility, Want } from '@kit.AbilityKit';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||
import { resourceManager } from '@kit.LocalizationKit';
|
||||
import { util } from '@kit.ArkTS';
|
||||
|
||||
let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator;
|
||||
let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs;
|
||||
let jsonPath: string = 'mock/mock-config.json';
|
||||
let tag: string = 'testTag';
|
||||
|
||||
async function onAbilityCreateCallback(data: UIAbility) {
|
||||
hilog.info(0x0000, 'testTag', 'onAbilityCreateCallback, data: ${}', JSON.stringify(data));
|
||||
}
|
||||
|
||||
async function addAbilityMonitorCallback(err: BusinessError) {
|
||||
hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
|
||||
}
|
||||
|
||||
export default class OpenHarmonyTestRunner implements TestRunner {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
onPrepare() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare');
|
||||
}
|
||||
|
||||
async onRun() {
|
||||
let tag = 'testTag';
|
||||
hilog.info(0x0000, tag, '%{public}s', 'OpenHarmonyTestRunner onRun run');
|
||||
abilityDelegatorArguments = abilityDelegatorRegistry.getArguments()
|
||||
abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator()
|
||||
let moduleName = abilityDelegatorArguments.parameters['-m'];
|
||||
let context = abilityDelegator.getAppContext().getApplicationContext().createModuleContext(moduleName);
|
||||
let mResourceManager = context.resourceManager;
|
||||
await checkMock(abilityDelegator, mResourceManager);
|
||||
const bundleName = abilityDelegatorArguments.bundleName;
|
||||
const testAbilityName: string = 'TestAbility';
|
||||
let lMonitor: abilityDelegatorRegistry.AbilityMonitor = {
|
||||
abilityName: testAbilityName,
|
||||
onAbilityCreate: onAbilityCreateCallback,
|
||||
moduleName: moduleName
|
||||
};
|
||||
abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
|
||||
const want: Want = {
|
||||
bundleName: bundleName,
|
||||
abilityName: testAbilityName,
|
||||
moduleName: moduleName
|
||||
};
|
||||
abilityDelegator.startAbility(want, (err: BusinessError, data: void) => {
|
||||
hilog.info(0x0000, tag, 'startAbility : err : %{public}s', JSON.stringify(err) ?? '');
|
||||
hilog.info(0x0000, tag, 'startAbility : data : %{public}s', JSON.stringify(data) ?? '');
|
||||
})
|
||||
hilog.info(0x0000, tag, '%{public}s', 'OpenHarmonyTestRunner onRun end');
|
||||
}
|
||||
}
|
||||
|
||||
async function checkMock(abilityDelegator: abilityDelegatorRegistry.AbilityDelegator, resourceManager: resourceManager.ResourceManager) {
|
||||
let rawFile: Uint8Array;
|
||||
try {
|
||||
rawFile = resourceManager.getRawFileContentSync(jsonPath);
|
||||
hilog.info(0x0000, tag, 'MockList file exists');
|
||||
let mockStr: string = util.TextDecoder.create("utf-8", { ignoreBOM: true }).decodeWithStream(rawFile);
|
||||
let mockMap: Record<string, string> = getMockList(mockStr);
|
||||
try {
|
||||
abilityDelegator.setMockList(mockMap)
|
||||
} catch (error) {
|
||||
let code = (error as BusinessError).code;
|
||||
let message = (error as BusinessError).message;
|
||||
hilog.error(0x0000, tag, `abilityDelegator.setMockList failed, error code: ${code}, message: ${message}.`);
|
||||
}
|
||||
} catch (error) {
|
||||
let code = (error as BusinessError).code;
|
||||
let message = (error as BusinessError).message;
|
||||
hilog.error(0x0000, tag, `ResourceManager:callback getRawFileContent failed, error code: ${code}, message: ${message}.`);
|
||||
}
|
||||
}
|
||||
|
||||
function getMockList(jsonStr: string) {
|
||||
let jsonObj: Record<string, Object> = JSON.parse(jsonStr);
|
||||
let map: Map<string, object> = new Map<string, object>(Object.entries(jsonObj));
|
||||
let mockList: Record<string, string> = {};
|
||||
map.forEach((value: object, key: string) => {
|
||||
let realValue: string = value['source'].toString();
|
||||
mockList[key] = realValue;
|
||||
});
|
||||
hilog.info(0x0000, tag, '%{public}s', 'mock-json value:' + JSON.stringify(mockList) ?? '');
|
||||
return mockList;
|
||||
}
|
36
code/BasicFeature/Security/Asset/entry/src/ohosTest/module.json5
Executable file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"module": {
|
||||
"name": "entry_test",
|
||||
"type": "feature",
|
||||
"description": "$string:module_test_desc",
|
||||
"mainElement": "TestAbility",
|
||||
"deviceTypes": [
|
||||
"default"
|
||||
],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false,
|
||||
"pages": "$profile:test_pages",
|
||||
"abilities": [
|
||||
{
|
||||
"name": "TestAbility",
|
||||
"srcEntry": "./ets/testability/TestAbility.ets",
|
||||
"description": "$string:TestAbility_desc",
|
||||
"icon": "$media:icon",
|
||||
"label": "$string:TestAbility_label",
|
||||
"exported": true,
|
||||
"startWindowIcon": "$media:icon",
|
||||
"startWindowBackground": "$color:start_window_background",
|
||||
"skills": [
|
||||
{
|
||||
"actions": [
|
||||
"action.system.home"
|
||||
],
|
||||
"entities": [
|
||||
"entity.system.home"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"color": [
|
||||
{
|
||||
"name": "start_window_background",
|
||||
"value": "#FFFFFF"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_test_desc",
|
||||
"value": "test ability description"
|
||||
},
|
||||
{
|
||||
"name": "TestAbility_desc",
|
||||
"value": "the test ability"
|
||||
},
|
||||
{
|
||||
"name": "TestAbility_label",
|
||||
"value": "test label"
|
||||
}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 2.0 KiB |
@ -0,0 +1,5 @@
|
||||
{
|
||||
"src": [
|
||||
"testability/pages/Index"
|
||||
]
|
||||
}
|
18
code/BasicFeature/Security/Asset/hvigor/hvigor-config.json5
Executable file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"hvigorVersion": "4.0.1",
|
||||
"dependencies": {
|
||||
"@ohos/hvigor-ohos-plugin": "4.0.1"
|
||||
},
|
||||
"execution": {
|
||||
// "daemon": true, /* Enable daemon compilation. Default: true */
|
||||
// "incremental": true, /* Enable incremental compilation. Default: true */
|
||||
// "parallel": true, /* Enable parallel compilation. Default: true */
|
||||
// "typeCheck": false, /* Enable typeCheck. Default: false */
|
||||
},
|
||||
"logging": {
|
||||
// "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
|
||||
},
|
||||
"debugging": {
|
||||
// "stacktrace": false /* Disable stacktrace compilation. Default: false */
|
||||
}
|
||||
}
|
1
code/BasicFeature/Security/Asset/hvigor/hvigor-wrapper.js
Executable file
6
code/BasicFeature/Security/Asset/hvigorfile.ts
Executable file
@ -0,0 +1,6 @@
|
||||
import { appTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
|
||||
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
|
||||
}
|
63
code/BasicFeature/Security/Asset/hvigorw
Executable file
@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Hvigor startup script, version 1.0.0
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# NODE_HOME - location of a Node home dir
|
||||
# or
|
||||
# Add /usr/local/nodejs/bin to the PATH environment variable
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
HVIGOR_APP_HOME="`pwd -P`"
|
||||
HVIGOR_WRAPPER_SCRIPT=${HVIGOR_APP_HOME}/hvigor/hvigor-wrapper.js
|
||||
warn() {
|
||||
echo ""
|
||||
echo -e "\033[1;33m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo ""
|
||||
echo -e "\033[1;31m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
|
||||
}
|
||||
|
||||
fail() {
|
||||
error "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Determine node to start hvigor wrapper script
|
||||
if [ -n "${NODE_HOME}" ];then
|
||||
EXECUTABLE_NODE="${NODE_HOME}/bin/node"
|
||||
if [ ! -x "$EXECUTABLE_NODE" ];then
|
||||
fail "ERROR: NODE_HOME is set to an invalid directory,check $NODE_HOME\n\nPlease set NODE_HOME in your environment to the location where your nodejs installed"
|
||||
fi
|
||||
else
|
||||
EXECUTABLE_NODE="node"
|
||||
which ${EXECUTABLE_NODE} > /dev/null 2>&1 || fail "ERROR: NODE_HOME is not set and not 'node' command found in your path"
|
||||
fi
|
||||
|
||||
# Check hvigor wrapper script
|
||||
if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ];then
|
||||
fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}"
|
||||
fi
|
||||
|
||||
# start hvigor-wrapper script
|
||||
exec "${EXECUTABLE_NODE}" \
|
||||
"${HVIGOR_WRAPPER_SCRIPT}" "$@"
|
77
code/BasicFeature/Security/Asset/hvigorw.bat
Executable file
@ -0,0 +1,77 @@
|
||||
:: Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
:: Licensed under the Apache License, Version 2.0 (the "License");
|
||||
:: you may not use this file except in compliance with the License.
|
||||
:: You may obtain a copy of the License at
|
||||
::
|
||||
:: http://www.apache.org/licenses/LICENSE-2.0
|
||||
::
|
||||
:: Unless required by applicable law or agreed to in writing, software
|
||||
:: distributed under the License is distributed on an "AS IS" BASIS,
|
||||
:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
:: See the License for the specific language governing permissions and
|
||||
:: limitations under the License.
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Hvigor startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js
|
||||
set NODE_EXE=node.exe
|
||||
|
||||
goto start
|
||||
|
||||
:start
|
||||
@rem Find node.exe
|
||||
if defined NODE_HOME goto findNodeFromNodeHome
|
||||
|
||||
%NODE_EXE% --version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the NODE_HOME variable in your environment to match the
|
||||
echo location of your NodeJs installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findNodeFromNodeHome
|
||||
set NODE_HOME=%NODE_HOME:"=%
|
||||
set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE%
|
||||
|
||||
if exist "%NODE_EXE_PATH%" goto execute
|
||||
echo.
|
||||
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the NODE_HOME variable in your environment to match the
|
||||
echo location of your NodeJs installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Execute hvigor
|
||||
"%NODE_EXE%" "%WRAPPER_MODULE_PATH%" %*
|
||||
|
||||
if "%ERRORLEVEL%" == "0" goto hvigorwEnd
|
||||
|
||||
:fail
|
||||
exit /b 1
|
||||
|
||||
:hvigorwEnd
|
||||
if "%OS%" == "Windows_NT" endlocal
|
||||
|
||||
:end
|
15
code/BasicFeature/Security/Asset/oh-package-lock.json5
Executable file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"lockfileVersion": 3,
|
||||
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
|
||||
"specifiers": {
|
||||
"@ohos/hypium@1.0.6": "@ohos/hypium@1.0.6"
|
||||
},
|
||||
"packages": {
|
||||
"@ohos/hypium@1.0.6": {
|
||||
"integrity": "sha512-bb3DWeWhYrFqj9mPFV3yZQpkm36kbcK+YYaeY9g292QKSjOdmhEIQR2ULPvyMsgSR4usOBf5nnYrDmaCCXirgQ==",
|
||||
"resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.6.tgz",
|
||||
"shasum": "3f5fed65372633233264b3447705b0831dfe7ea1",
|
||||
"registryType": "ohpm"
|
||||
}
|
||||
}
|
||||
}
|
28
code/BasicFeature/Security/Asset/oh-package.json5
Executable file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
{
|
||||
"license": "",
|
||||
"devDependencies": {
|
||||
"@ohos/hypium": "1.0.6"
|
||||
},
|
||||
"author": "",
|
||||
"name": "asset_sample",
|
||||
"description": "Please describe the basic information.",
|
||||
"main": "",
|
||||
"version": "1.0.0",
|
||||
"dynamicDependencies": {},
|
||||
"dependencies": {}
|
||||
}
|
BIN
code/BasicFeature/Security/Asset/screenshots/batch_query_result.jpeg
Executable file
After Width: | Height: | Size: 45 KiB |
BIN
code/BasicFeature/Security/Asset/screenshots/delete.jpeg
Executable file
After Width: | Height: | Size: 36 KiB |
BIN
code/BasicFeature/Security/Asset/screenshots/query.jpeg
Executable file
After Width: | Height: | Size: 36 KiB |
BIN
code/BasicFeature/Security/Asset/screenshots/save.jpeg
Executable file
After Width: | Height: | Size: 39 KiB |
BIN
code/BasicFeature/Security/Asset/screenshots/single_query_result.jpeg
Executable file
After Width: | Height: | Size: 28 KiB |
BIN
code/BasicFeature/Security/Asset/screenshots/update_edit.jpeg
Executable file
After Width: | Height: | Size: 37 KiB |
BIN
code/BasicFeature/Security/Asset/screenshots/update_list.jpeg
Executable file
After Width: | Height: | Size: 32 KiB |