From 473b450911f693f60bca2893ed19475e56b12a12 Mon Sep 17 00:00:00 2001 From: Annie_wang Date: Thu, 5 Jan 2023 14:37:11 +0800 Subject: [PATCH] update docs Signed-off-by: Annie_wang --- en/application-dev/security/Readme-EN.md | 3 +- .../security/accesstoken-guidelines.md | 235 ++++++++++++------ .../security/accesstoken-overview.md | 38 +-- .../app-provision-structure.md | 72 +++--- .../figures/permission-read_calendar.png | Bin 0 -> 23640 bytes 5 files changed, 221 insertions(+), 127 deletions(-) rename en/application-dev/{quick-start => security}/app-provision-structure.md (61%) create mode 100644 en/application-dev/security/figures/permission-read_calendar.png diff --git a/en/application-dev/security/Readme-EN.md b/en/application-dev/security/Readme-EN.md index ce9f1dd695..05d2d2864d 100644 --- a/en/application-dev/security/Readme-EN.md +++ b/en/application-dev/security/Readme-EN.md @@ -8,7 +8,7 @@ - User Authentication - [User Authentication Overview](userauth-overview.md) - [User Authentication Development](userauth-guidelines.md) -- Key Management +- HUKS - [HUKS Overview](huks-overview.md) - [HUKS Development](huks-guidelines.md) - Crypto Framework @@ -20,3 +20,4 @@ - hapsigner - [hapsigner Overview](hapsigntool-overview.md) - [hapsigner Guide](hapsigntool-guidelines.md) + - [HarmonyAppProvision Configuration File](app-provision-structure.md) \ No newline at end of file diff --git a/en/application-dev/security/accesstoken-guidelines.md b/en/application-dev/security/accesstoken-guidelines.md index c46c8fc828..0e45400d14 100644 --- a/en/application-dev/security/accesstoken-guidelines.md +++ b/en/application-dev/security/accesstoken-guidelines.md @@ -2,58 +2,46 @@ ## When to Use -In this example, the app requires the **ohos.permission.PERMISSION1** and **ohos.permission.PERMISSION2** permissions to implement core functions. +The [Ability Privilege Level (APL)](accesstoken-overview.md#app-apls) of an application can be **normal**, **system_basic**, or **system_core**. The default APL is **normal**. The [permission types](accesstoken-overview.md#permission-types) include **system_grant** and **user_grant**. For details about the permissions for apps, see the [App Permission List](permission-list.md). -- The ability privilege level (APL) of the app is **normal**. -- The level of **ohos.permission.PERMISSION1** is **normal**, and the authorization mode is **system_grant**. -- The level of **ohos.permission.PERMISSION2** is **system_basic**, and the authorization mode is **user_grant**. +This document describes the following operations: -> **CAUTION** -> -> In this scenario, the required permissions include a **user_grant** permission. You can check whether the caller has the required permission through permission verification. -> -> If the permission verification result indicates that the app has not obtained that permission, dynamic user authorization is required. +- [Declaring Permissions in the Configuration File](#declaring-permissions-in-the-configuration-file) +- [Declaring Permissions in the ACL](#declaring-permissions-in-the-acl) +- [Requesting User Authorization](#requesting-user-authorization) +- [Pre-Authorizing user_grant Permissions](#pre-authorizing-user_grant-permissions) -## Available APIs +## Declaring Permissions in the Configuration File -The table below lists only the API used in this guide. For more information, see [Ability Access control](../reference/apis/js-apis-ability-context.md). +During the development, you need to declare the permissions required by your application one by one in the project configuration file. The application cannot obtain the permissions that are not declared in the configuration file. OpenHarmony provides two application models: FA model and stage model. For more information, see Application Models. The application bundle and configuration file vary with the application model. -| API | Description | -| ------------------------------------------------------------ | --------------------------------------------------- | -| requestPermissionsFromUser(permissions: Array<string>, requestCallback: AsyncCallback<PermissionRequestResult>) : void; | Requests permissions from the user by displaying a dialog box. This API uses an asynchronous callback to return the result.| +> **NOTE**
The default APL of an application is **normal**. When an application needs the **system_basic** or **system_core** APL, you must declare the permission in the configuration file and the [Access Control List (ACL)](#declaring-permissions-in-the-acl). -## Declaring Permissions +The following table describes the fields in the configuration file. -Declare the permissions required by the app one by one in the project configuration file. The app cannot obtain the permissions that are not declared in the configuration file. The ability framework provides two models: Feature Ability (FA) model and stage model. For more information, see [Ability Framework Overview](../ability/ability-brief.md). +| Field | Mandatory| Description | +| --------- | -------- | ------------------------------------------------------------ | +| name | Yes | Name of the permission. | +| reason | No | Reason for requesting the permission.
This field is mandatory when the requested permission needs user authorization (user_grant).| +| usedScene | No | Application scenario of the permission.
This field is mandatory when the requested permission needs user authorization (user_grant).| +| abilities | No | Abilities that require the permission. The value is an array.
**Applicable model**: stage| +| ability | No | Abilities that require the permission. The value is an array.
**Applicable model**: FA| +| when | No | Time when the permission is used.
Value:
- **inuse**: The permission applies only to a foreground application.
- **always**: The permission applies to both the foreground and background applications.| -Note that the app bundle structure and configuration file vary with the ability framework model. - -The following table describes the tags in the configuration file. - -| Field | Description | -| --------- | ------------------------------------------------------------ | -| name | Name of the permission. | -| reason | Reason for requesting the permission. This field is mandatory for a user_grant permission.| -| usedScene | Scenario of the permission. This field is mandatory for a user_grant permission.| -| ability | Abilities that use the permission. The value is an array.
**Applicable model**: FA | -| abilities | Abilities that use the permission. The value is an array.
**Applicable model**: stage | -| when | Time when the permission is used. The value can be **inuse** (the permission can be used only in the foreground) or **always** (the permission can be used in foreground and background).| - -### FA Model - -For the apps based on the FA model, declare the required permissions in the **config.json** file. +### Stage Model -**Example** +If the application is based on the stage model, declare the permissions in [**module.json5**](../quick-start/module-configuration-file.md). ```json { "module" : { - "reqPermissions":[ + // ... + "requestPermissions":[ { "name" : "ohos.permission.PERMISSION1", "reason": "$string:reason", "usedScene": { - "ability": [ + "abilities": [ "FormAbility" ], "when":"inuse" @@ -63,7 +51,7 @@ For the apps based on the FA model, declare the required permissions in the **co "name" : "ohos.permission.PERMISSION2", "reason": "$string:reason", "usedScene": { - "ability": [ + "abilities": [ "FormAbility" ], "when":"always" @@ -74,21 +62,20 @@ For the apps based on the FA model, declare the required permissions in the **co } ``` -### Stage Model - -For the apps based on the stage model, declare the required permissions in the **module.json5** file. +### FA Model -**Example** +If the application is based on the FA model, declare the required permissions in **config.json**. ```json { "module" : { - "requestPermissions":[ + // ... + "reqPermissions":[ { "name" : "ohos.permission.PERMISSION1", "reason": "$string:reason", "usedScene": { - "abilities": [ + "ability": [ "FormAbility" ], "when":"inuse" @@ -98,7 +85,7 @@ For the apps based on the stage model, declare the required permissions in the * "name" : "ohos.permission.PERMISSION2", "reason": "$string:reason", "usedScene": { - "abilities": [ + "ability": [ "FormAbility" ], "when":"always" @@ -109,60 +96,152 @@ For the apps based on the stage model, declare the required permissions in the * } ``` -## Declaring the ACL - -The permission level of **ohos.permission.PERMISSION2** is **system_basic**, which is higher than the app's APL. In this case, use the ACL. +## Declaring Permissions in the ACL -In addition to declaring all the permissions in the configuration file, you must declare the permissions whose levels are higher that the app's APL in the app's profile. For details about the fields in the profile, see [HarmonyAppProvision Configuration File](../quick-start/app-provision-structure.md). +If an application of the **normal** level requires permissions corresponding to the **system_basic** or **system_core** level, you need to declare the required permissions in the ACL. -For example, declare the required permission in the **acls** field: +For example, if an application needs to access audio files of a user and capture screenshots, it requires the **ohos.permission.WRITE_AUDIO** permission (of the **system_basic** level) and the **ohos.permission.CAPTURE_SCREEN** permission (of the **system_core** level). In this case, you need to add the related permissions to the **acl** field in the [HarmonyAppProvision configuration file](app-provision-structure.md). ```json { - "acls": { - "allowed-acls": [ - "ohos.permission.PERMISSION2" - ] - } + // ... + "acls":{ + "allowed-acls":[ + "ohos.permission.WRITE_AUDIO", + "ohos.permission.CAPTURE_SCREEN" + ] + } } ``` -## Applying for the user_grant Permission - -After the permissions are declared, the system grants the system_grant permission during the installation of the app. The user_grant permission must be authorized by the user. +## Requesting User Authorization -Therefore, before allowing the app to call the API protected by the **ohos.permission.PERMISSION2** permission, the system needs to verify whether the app has the permission to do so. +If an application needs to access user privacy information or use system abilities, for example, accessing location or calendar information or using the camera to take photos or record videos, it must request the permission from users. A permission verification is performed first to determine whether the current invoker has the corresponding permission. If the application has not obtained that permission, a dialog box will be displayed to request user authorization. The following figure shows an example. + -If the verification result indicates that the app has the permission, the app can access the target API. Otherwise, the app needs to request user authorization and then proceeds based on the authorization result. For details, see [Access Control Overview](accesstoken-overview.md). +> **NOTE**
Each time before an API protected by a permission is accessed, the **requestPermissionsFromUser()** API will be called to request user authorization. After a permission is dynamically granted, the user may revoke the permission. Therefore, the previously granted authorization status cannot be persistent. -> **CAUTION** -> -> The permission authorized by a user is not permanent, because the user may revoke the authorization at any time. Each time before the API protected by the permission is called, call **requestPermissionsFromUser()** to request the permission. +### Stage Model -## Example +Example: Request the permission to read calendar information for an app. + +1. Apply for the **ohos.permission.READ_CALENDAR** permission. For details, see [Declaring Permissions in the Configuration File](#declaring-permissions-in-the-configuration-file). + +2. Call **requestPermissionsFromUser()** in the **onWindowStageCreate()** callback of the UIAbility to dynamically apply for the permission, or request user authorization on the UI based on service requirements. The return value of **requestPermissionsFromUser()** indicates whether the application has the target permission. If yes, the target API can be called normally. + + Request user authorization in UIAbility. + + ```typescript + import UIAbility from '@ohos.app.ability.UIAbility'; + import Window from '@ohos.window'; + import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; + import { Permissions } from '@ohos.abilityAccessCtrl'; + + export default class EntryAbility extends UIAbility { + // ... + + onWindowStageCreate(windowStage: Window.WindowStage) { + // Main window is created, set main page for this ability + let context = this.context; + let AtManager = abilityAccessCtrl.createAtManager(); + // The return value of requestPermissionsFromUser determines whether to display a dialog box to request user authorization. + const permissions: Array = ['ohos.permission.READ_CALENDAR']; + AtManager.requestPermissionsFromUser(context, permissions).then((data) => { + console.info(`[requestPermissions] data: ${JSON.stringify(data)}`); + let grantStatus: Array = data.authResults; + if (grantStatus[0] === -1) { + // The authorization fails. + } else { + // The authorization is successful. + } + }).catch((err) => { + console.error(`[requestPermissions] Failed to start request permissions. Error: ${JSON.stringify(err)}`); + }) + + // ... + } + } + ``` + + Request user authorization on the UI. + ```typescript + import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; + import { Permissions } from '@ohos.abilityAccessCtrl'; + import common from '@ohos.app.ability.common'; + + @Entry + @Component + struct Index { + reqPermissions() { + let context = getContext(this) as common.UIAbilityContext; + let AtManager = abilityAccessCtrl.createAtManager(); + // The return value of requestPermissionsFromUser determines whether to display a dialog box to request user authorization. + const permissions: Array = ['ohos.permission.READ_CALENDAR']; + AtManager.requestPermissionsFromUser(context, permissions).then((data) => { + console.info(`[requestPermissions] data: ${JSON.stringify(data)}`); + let grantStatus: Array = data.authResults; + if (grantStatus[0] === -1) { + // The authorization fails. + } else { + // The authorization is successful. + } + }).catch((err) => { + console.error(`[requestPermissions] Failed to start request permissions. Error: ${JSON.stringify(err)}`); + }) + } + + // Page display. + build() { + // ... + } + } + ``` -The procedure for requesting user authorization is as follows: +### FA Model -1. Obtain the ability context. -2. Call **requestPermissionsFromUser()** to request user authorization. The API determines whether to display a dialog box to request user authorization based on whether the app has the permission. -3. Check whether the app has the permission based on the return value. If the app has the permission, the API can be invoked. +Call [requestPermissionsFromUser()](../reference/apis/js-apis-inner-app-context.md#contextrequestpermissionsfromuser7) to request user authorization. ```js - // OnWindowStageCreate of the ability - onWindowStageCreate() { - var context = this.context +// onWindowStageCreate() of Ability +onWindowStageCreate() { + let context = this.context; let array:Array = ["ohos.permission.PERMISSION2"]; - // requestPermissionsFromUser determines whether to display a dialog box based on the permission authorization status. + // The return value of requestPermissionsFromUser determines whether to display a dialog box to request user authorization. context.requestPermissionsFromUser(array).then(function(data) { - console.log("data type:" + typeof(data)); - console.log("data:" + data); - console.log("data permissions:" + data.permissions); - console.log("data result:" + data.authResults); + console.log("data:" + JSON.stringify(data)); + console.log("data permissions:" + JSON.stringify(data.permissions)); + console.log("data result:" + JSON.stringify(data.authResults)); }, (err) => { - console.error('Failed to start ability', err.code); + console.error('Failed to start ability', err.code); }); - } +} +``` +## Pre-Authorizing user_grant Permissions +By default, the **user_grant** permissions must be dynamically authorized by the user through a dialog box. However, for pre-installed apps, you can pre-authroize the permissions, for example, the **ohos.permission.MICROPHONE** permission, in the [**install_list_permission.json**](https://gitee.com/openharmony/vendor_hihope/blob/master/rk3568/preinstall-config/install_list_permissions.json) file to prevent the user authorization dialog box from being displayed. The **install_list_permissions.json** file is in the **/system/etc/app/** directory on a device. When the device is started, the **install_list_permissions.json** file is loaded. When the application is installed, the **user_grant** permissions in the file are granted. The **install_list_permissions.json** file contains the following fields: +- **bundleName**: bundle name of the application. +- `app_signature`: fingerprint information of the application. For details, see [Application Privilege Configuration Guide](../../device-dev/subsystems/subsys-app-privilege-config-guide.md#configuration-in-install-list-capabilityjson). +- **permissions**: **name** specifies the name of the **user_grant** permission to pre-authorize. **userCancellable** specifies whether the user can revoke the pre-authorization. The value **true** means the user can revoke the pre-authorization; the vaue **false** means the opposite. + +> **NOTE**
This file is available only for preinstalled applications. + +```json +[ + // ... + { + "bundleName": "com.example.myapplication", // Bundle Name. + "app_signature": ["****"], // Fingerprint information. + "permissions":[ + { + "name": "ohos.permission.PERMISSION_X", // Permission to pre-authorize. + "userCancellable": false // The user cannot revoke the authorization. + }, + { + "name": "ohos.permission.PERMISSION_X", // Permission to pre-authorize. + "userCancellable": true // The user can revoke the authorization. + } + ] + } +] ``` -> **NOTE**
-> For details about the APIs, see [AbilityContext](../reference/apis/js-apis-ability-context.md). + \ No newline at end of file diff --git a/en/application-dev/security/accesstoken-overview.md b/en/application-dev/security/accesstoken-overview.md index 9e8aa2a655..e42543a356 100644 --- a/en/application-dev/security/accesstoken-overview.md +++ b/en/application-dev/security/accesstoken-overview.md @@ -2,14 +2,14 @@ OpenHarmony AccessTokenManager (ATM) implements unified app permission management based on access tokens. -By default, apps can access limited system resources. However, in some cases, an app needs to access excess data (including personal data) and functions of the system or another app to implement extended functions. The system or apps must also explicitly share their data or functions through APIs. OpenHarmony uses app permissions to perform access control and prevent improper or malicious use of these data or functions. +By default, apps can access limited system resources. However, to provide extended features, an app may need to access excess data (including personal data) and functions of the system or another app. The system or apps must also explicitly share their data or functions through APIs. OpenHarmony uses app permissions to perform access control and prevent improper or malicious use of these data or functions. App permissions are used to protect the following objects: - Data: personal data (such as photos, contacts, calendar, and location), device data (such as device ID, camera, and microphone), and app data. - Functions: device functions (such as making calls, sending SMS messages, and connecting to the Internet) and app functions (such as displaying windows and creating shortcuts). -Without the required permissions, an app cannot access or perform operations on the target object. Permissions must be clearly defined for apps. With well-defined app permissions, the system can standardize the behavior of apps and protect user privacy. Before an app accesses the target object, the target object verifies the app's permissions and denies the access if the app does not have required permissions. +Without the required permissions, an app cannot access or perform operations on the target object. Permissions must be clearly defined for apps. With well-defined app permissions, the system can standardize app behavior and protect user privacy. Before an app accesses the target object, the target object verifies the app's permissions and denies the access if the app does not have required permissions. Currently, ATM verifies app permissions based on the token identity (token ID). A token ID identifies an app. ATM manages app permissions based on the app's token ID. @@ -17,13 +17,13 @@ Currently, ATM verifies app permissions based on the token identity (token ID). Observe the following principles for permission management: -- Provide clear description about the app functions and scenarios for each permission required by the app so that users can clearly know why and when these permissions are required. Do not induce or mislead users' authorization. The permissions on an app must comply with the description provided in the app. +- Provide clear description about the functions and scenarios for each permission required by the app so that users can clearly know why and when these permissions are needed. Do not induce or mislead users' authorization. The permissions on an app must comply with the description provided in the app. - Use the principle of least authority for user permissions. Allow only necessary permissions for service functions. - When an app is started for the first time, avoid frequently displaying dialog boxes to request multiple permissions. Allow the app to apply for the permission only when it needs to use the corresponding service function. - If a user rejects to grant a permission, the user can still use functions irrelevant to this permission and can register and access the app. - Provide no more message if a user rejects the authorization required by a function. Provide onscreen instructions to direct the user to grant the permission in **Settings** if the user triggers this function again or needs to use this function. -- All the permissions granted to apps must come from the [App Permission List](permission-list.md). Custom permissions are not allowed for apps currently. +- All the permissions granted to apps must come from the [App Permission List](permission-list.md). Custom permissions are not allowed currently. ## Permission Workflows @@ -50,7 +50,9 @@ The figure below illustrates the process. 3. A low-APL app can have a high-level permission by using the Access Control List (ACL). For details, see [ACL](#acl). ### Permission Verification -To protect sensitive data and eliminate security threads on core abilities, you can use the permissions in the [App Permission List](permission-list.md) to protect the related API from unauthorized calling. Each time before the API is called, a permission verification is performed to check whether the caller has the required permission. The API can be called only after the permission verification is successful. +To protect sensitive data and eliminate security threads on core abilities, you can use the permissions in the [App Permission List](permission-list.md) to protect an API from unauthorized calling. Each time before the API is called, a permission verification is performed to check whether the caller has the required permission. + +The API can be called only after the permission verification is successful. The figure below shows the permission verification process. @@ -58,7 +60,7 @@ The figure below shows the permission verification process. 1: An app permission can be used to control the access to an API that has sensitive data involved or security threats on the core abilities. -2: Select the permission from the [App Permission List](permission-list.md). For example, if contact information is involved in an API provided by an app, you can use the contact-related permissions to protect the API. +2: The API can be protected by a permission in the [ACL](#acl). For example, if contact information is involved in an API provided by an app, you can use the contact-related permissions to protect the API. 3: Use **verifyAccessToken()** to check whether the caller has the required permission. For details, see [Permission Verification Guide](permission-verify-guidelines.md). @@ -88,7 +90,7 @@ Then, use the [hapsigner](hapsigntool-overview.md) tool to generate a certificat The following is an example. -This example shows only the modification of the **apl** field. Set other fields based on your requirements. For details about the fields in the profile, see [HarmonyAppProvision Configuration File](../quick-start/app-provision-structure.md). +This example shows only the modification of the **apl** field. Set other fields based on your requirements. For details about the fields in the profile, see [HarmonyAppProvision Configuration File](app-provision-structure.md). ```json { @@ -123,7 +125,7 @@ The permissions open to apps vary with the permission level. The permission leve The system_core permission allows access to core resources of the OS. These resources are underlying core services of the system. If these resources are corrupted, the OS cannot run properly. - The system_core permissions are not open to third-party apps currently. + The system_core permissions are not open to third-party apps. ## Permission Types @@ -131,19 +133,19 @@ Permissions can be classified into the following types based on the authorizatio - **system_grant** - The app permissions are authorized by the system. This type of apps cannot access user or device sensitive information. The allowed operations have minor impact on the system or other apps. + The app permissions are authorized by the system. Apps granted with this type of permission cannot access user or device sensitive information, and the operations allowed for them have minor impact on the system or other apps. - For a system_grant app, the system automatically grants the required permissions to the app when the app is installed. The system_grant permission list must be presented to users on the details page of the app in the app store. + For a system_grant app, the system automatically grants the required permissions to the app when the app is installed. The system_grant permission list must be presented to users on the details page of the app in the app market. - **user_grant** - The app permissions must be authorized by users. This type of apps may access user or device sensitive information. The allowed operations may have a critical impact on the system or other apps. + The app permissions must be authorized by users. Apps granted with this type of permissions may access user or device sensitive information, and the operations allowed for them may have a critical impact on the system or other apps. This type of permissions must be declared in the app installation package and authorized by users dynamically during the running of the app. The app has the permission only after user authorization. - For example, in the [App Permission List](permission-list.md), the permissions for microphones and cameras are user_grant. The list provides reasons for using the permissions. + For example, as described in the [App Permission List](permission-list.md), the permissions for microphones and cameras are user_grant. The list provides reasons for using the permissions. - The user_grant permission list must also be presented on the details page of the app in the app store. + The user_grant permission list must also be presented on the details page of the app in the app market. ### Authorization Processes @@ -173,7 +175,7 @@ The procedure is as follows: **Precautions** - Check the app's permission each time before the operation requiring the permission is performed. -- To check whether a user has granted specific permissions to an app, use the [verifyAccessToken](../reference/apis/js-apis-abilityAccessCtrl.md) method. This method returns [PERMISSION_GRANTED](../reference/apis/js-apis-abilityAccessCtrl.md) or [PERMISSION_DENIED](../reference/apis/js-apis-abilityAccessCtrl.md). For details about the sample code, see [Access Control Development](accesstoken-guidelines.md). +- To check whether a user has granted specific permissions to an app, use the [verifyAccessToken](../reference/apis/js-apis-abilityAccessCtrl.md) API. This API returns [PERMISSION_GRANTED](../reference/apis/js-apis-abilityAccessCtrl.md) or [PERMISSION_DENIED](../reference/apis/js-apis-abilityAccessCtrl.md). For details about the sample code, see [Access Control Development](accesstoken-guidelines.md). - Users must be able to understand and control the authorization of user_grant permissions. During the running process, the app requiring user authorization must proactively call an API to dynamically request the authorization. Then, the system displays a dialog box asking the user to grant the permission. The user will determine whether to grant the permission based on the running context of the app. - The permission authorized is not permanent, because the user may revoke the authorization at any time. Therefore, even if the user has granted the requested permission to the app, the app must check for the permission before calling the API controlled by this permission. @@ -190,15 +192,15 @@ The APL of app A is **normal**. App A needs to have permission B (system_basic l In this case, you can use the ACL to grant permission B to app A. For details, see [Using the ACL](#using-the-acl). -For details about whether a permission can be enabled through the ACL, see the [App Permission List](permission-list.md). +For details about whether a permission can be enabled through the ACL, see [App Permission List](permission-list.md). ### Using the ACL -If the permission required by an app has higher level than the app's APL, you can use the ACL to grant the permission required. +If the permission required by an app has a higher level than the app's APL, you can use the ACL to grant the permission required. In addition to the preceding [authorization processes](#authorization-processes), you must declare the ACL. -That is, you need to declare the required permissions in the app's configuration file, and [declare the ACL](accesstoken-guidelines.md#declaring-the-acl) in the app's profile. The subsequent steps of authorization are the same. +That is, you need to declare the required permissions in the app's configuration file, and [declare the ACL](accesstoken-guidelines.md#declaring-permissions-in-the-acl) in the app's profile. The subsequent steps of authorization are the same. **NOTICE** @@ -216,4 +218,4 @@ When developing an app installation package, you must declare the ACL in the **a } ``` -For details about the fields in the profile, see [HarmonyAppProvision Configuration File](../quick-start/app-provision-structure.md). +For details about the fields in the profile, see [HarmonyAppProvision Configuration File](app-provision-structure.md). diff --git a/en/application-dev/quick-start/app-provision-structure.md b/en/application-dev/security/app-provision-structure.md similarity index 61% rename from en/application-dev/quick-start/app-provision-structure.md rename to en/application-dev/security/app-provision-structure.md index df74f5fc03..d31cd6c690 100644 --- a/en/application-dev/quick-start/app-provision-structure.md +++ b/en/application-dev/security/app-provision-structure.md @@ -4,19 +4,19 @@ The **HarmonyAppProvision** configuration file (also called profile) is the file ## Configuration File Internal Structure The **HarmonyAppProvision** file consists of several parts, which are described in the table below. -**Table 1** Internal structure of the HarmonyAppProvision file -| Name | Description | Data Type| Mandatory| Initial Value Allowed| +| Name | Description | Data Type| Yes | Initial Value Allowed| | ----------- | ---------------------------------------------------------------------------------------- | -------- | -------- | -------- | | version-code | Version number of the **HarmonyAppProvision** file format. The value is a positive integer containing 32 or less digits.| Number | Yes| No | | version-name | Description of the version number. It is recommended that the value consist of three segments, for example, **A.B.C**. | String | Yes| No| -| uuid | Unique ID of the **HarmonyAppProvision** file. | String | Yes| No| +| uuid | Unique ID of the **HarmonyAppProvision** file. | String | Yes | No| | type | Type of the **HarmonyAppProvision** file. The value can be **debug** (for application debugging) or **release** (for application release). The recommended value is **debug**.| String | Yes| No| -| issuer | Issuer of the **HarmonyAppProvision** file. | String | Yes| No| +| issuer | Issuer of the **HarmonyAppProvision** file. | String | Yes | No| | validity | Validity period of the **HarmonyAppProvision** file. For details, see [Internal Structure of the validity Object](#internal-structure-of-the-validity-object). | Object | Yes | No | -| bundle-info | Information about the application bundle and developer. For details, see [Internal Structure of the bundle-info Object](#internal-structure-of-the-bundle-info-object). | Object | Yes| No | -| acls | Information about the Access Control Lists (ACLs). For details, see [Internal Structure of the acls Object](#internal-structure-of-the-acls-object). | Object | No| No | -| permissions | Permissions required for your application. For details, see [Internal Structure of the permissions Object](#internal-structure-of-the-permissions-object). | Object | No| No | -| debug-info | Additional information for application debugging. For details, see [Internal Structure of the debug-info Object](#internal-structure-of-the-debug-info-object). | Object | No| No | +| bundle-info | Information about the application bundle and developer. For details, see [Internal Structure of the bundle-info Object](#internal-structure-of-the-bundle-info-object). | Object | Yes | No | +| acls | Information about the Access Control Lists (ACLs). For details, see [Internal Structure of the acls Object](#internal-structure-of-the-acls-object). | Object | No | Yes | +| permissions | Permissions required for your application. For details, see [Internal Structure of the permissions Object](#internal-structure-of-the-permissions-object). | Object | No | Yes | +| debug-info | Additional information for application debugging. For details, see [Internal Structure of the debug-info Object](#internal-structure-of-the-debug-info-object). | Object | No | Yes | +| app-privilege-capabilities | Privilege information required by the application bundle. For details, see the [Application Privilege Configuration Guide](../../device-dev/subsystems/subsys-app-privilege-config-guide.md). | String array| No | Yes | An example of the **HarmonyAppProvision** file is as follows: ```json @@ -47,6 +47,7 @@ An example of the **HarmonyAppProvision** file is as follows: "device-id-type": "udid", "device-ids": ["string"] }, + "app-privilege-capabilities":["AllowAppUsePrivilegeExtension"], "issuer": "OpenHarmony" } @@ -54,46 +55,57 @@ An example of the **HarmonyAppProvision** file is as follows: ### Internal Structure of the validity Object -| Name | Description | Data Type| Mandatory| Initial Value Allowed| + +| Name | Description | Data Type| Mandatory | Initial Value Allowed| | ---------- | ------------------------------- | ------- | ------- | --------- | | not-before | Start time of the file validity period. The value is a Unix timestamp, which is a non-negative integer.| Number | Yes| No | | not-after | End time of the file validity period. The value is a Unix timestamp, which is a non-negative integer.| Number | Yes| No | ### Internal Structure of the bundle-info Object -| Name | Description | Data Type| Mandatory| Initial Value Allowed| + +| Name | Description | Data Type| Mandatory | Initial Value Allowed| | ------------------------ | ------------------------------- | ------- | -------- | --------- | -| developer-id | Unique ID of the developer.| String | Yes| No | -| development-certificate | Information about the [debug certificate](../security/hapsigntool-guidelines.md).| Number | Yes if **type** is set to **debug** and no otherwise | No | -| distribution-certificate | Information about the [release certificate](../security/hapsigntool-guidelines.md).| Number | Yes if **type** is set to **release** and no otherwise| No | -| bundle-name | Bundle name of the application.| String | Yes| No | -| apl | [Ability privilege level (APL)](../security/accesstoken-overview.md) of your application. The value can be **normal**, **system_basic**, or **system_core**.| String | Yes| No | -| app-feature | Type of your application. The value can be **hos_system_app** (system application) or **hos_normal_app** (non-system application).| String | Yes| No | +| developer-id | Unique ID of the developer.| String | Yes | No | +| development-certificate | Information about the [debug certificate](hapsigntool-guidelines.md).| Number | Yes if **type** is set to **debug** and no otherwise | No | +| distribution-certificate | Information about the [release certificate](hapsigntool-guidelines.md).| Number | Yes if **type** is set to **release** and no otherwise| No | +| bundle-name | Bundle name of the application.| String | Yes | No | +| apl | [Ability privilege level (APL)](accesstoken-overview.md) of your application. The value can be **normal**, **system_basic**, or **system_core**.| String | Yes | No | +| app-feature | Type of your application. The value can be **hos_system_app** (system application) or **hos_normal_app** (normal application). Only system applications are allowed to call system APIs. If a normal application calls a system API, the call cannot be successful or the application may run abnormally.| String | Yes | No | ### Internal Structure of the acls Object -The **acls** object contains the [ACLs](../security/accesstoken-overview.md) configured for your application. It should be noted that you still need to fill the ACL information in the **reqPermissions** attribute in the [config.json](package-structure.md) file. - -**Table 4** Internal structure of the acls object +The **acls** object contains the [ACL](accesstoken-overview.md) configured for your application. It should be noted that you still need to add the ACL information to the **requestPermissions** attribute in the application configuration file. -| Name | Description | Data Type| Mandatory| Initial Value Allowed| +| Name | Description | Data Type| Mandatory | Initial Value Allowed| | ------------------------ | ------------------------------- | ------- | ------- | --------- | | allowed-acls | [ACLs](../security/accesstoken-overview.md) configured for your application.| String array | No| No | ### Internal Structure of the permissions Object -The **permissions** object contains restricted permissions required for your application. Different from the ACLs set in the **acls** object, these permissions need user authorization during the running of your application. It should be noted that you still need to fill the permission information in the **reqPermissions** attribute in the [config.json](package-structure.md) file. +The **permissions** object contains restricted permissions required for your application. Different from the ACLs set in the **acls** object, these permissions need user authorization during the running of your application. It should be noted that you still need to add the ACL information to the **requestPermissions** attribute in the application configuration file. -**Table 5** Internal structure of the permissions object - -| Name | Description | Data Type| Mandatory| Initial Value Allowed| +| Name | Description | Data Type| Mandatory | Initial Value Allowed| | ------------------------ | ------------------------------- | ------- | ------- | --------- | -| restricted-permissions | [Restricted permissions](../security/accesstoken-overview.md) required for your application.| String array | No| No | +| restricted-permissions | [Restricted permissions](accesstoken-overview.md) required for your application.| String array | No | No | ### Internal Structure of the debug-info Object The **debug-info** object contains debugging information of your application, mainly device management and control information. -**Table 6** Internal structure of the debug-info object - -| Name | Description | Data Type| Mandatory| Initial Value Allowed| +| Name | Description | Data Type| Mandatory | Initial Value Allowed| | ------------------------ | ------------------------------- | ------- | ------- | --------- | -| device-id-type | Type of the device ID. Currently, only the udid type is supported.| String | No| No | -| device-ids | IDs of devices on which your application can be debugged.| String array | No| No | +| device-id-type | Type of the device ID. Currently, only the udid type is supported.| String | No | No | +| device-ids | IDs of devices on which your application can be debugged.| String array | Optional| No | + +## Modifying the HarmonyAppProvision Configuration File + +When a development project is created, the default application type is **hos_normal_app** and the default APL level is **normal**. + +To enable the application to use system APIs, you need to change the **app-feature** field to **hos_system_app** (system application). To apply for high-level permissions, you need to modify fields such as **apl** and **acl**. For details, see [Access Control Overview](accesstoken-overview.md). + + +To modify the HarmonyAppProvision configuration file, perform the following steps: + +1. Open the directory where the OpenHarmony SDK is located. (You can choose **File** > **Settings** > **OpenHarmony SDK** on the menu bar of DevEco Studio to query the directory.) +2. In the SDK directory, go to the **Toolchains** > {Version} > **lib** directory and open the **UnsgnedReleasedProfileTemplate.json** file. +3. Modify the related fields as required. + +After modifying the configuration file, [sign the application](hapsigntool-guidelines.md). diff --git a/en/application-dev/security/figures/permission-read_calendar.png b/en/application-dev/security/figures/permission-read_calendar.png new file mode 100644 index 0000000000000000000000000000000000000000..8236bcf2f28531c88362f1210cf70101740394bf GIT binary patch literal 23640 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 NCMc5@6{st^?$CUs8 literal 0 HcmV?d00001 -- GitLab