mirror of
https://gitee.com/openharmony/security_asset
synced 2024-11-30 03:20:23 +00:00
Merge branch 'master' of https://gitee.com/openharmony/security_asset
This commit is contained in:
commit
84e4590192
@ -22,6 +22,7 @@ members = [
|
||||
"services/core_service",
|
||||
"services/crypto_manager",
|
||||
"services/db_operator",
|
||||
"services/db_key_operator",
|
||||
"test/unittest/inner_api_rust",
|
||||
"test/unittest/module_test"
|
||||
]
|
||||
|
@ -2,7 +2,8 @@
|
||||
"jobs" : [{
|
||||
"name" : "post-fs-data",
|
||||
"cmds" : [
|
||||
"mkdir /data/service/el1/public/asset_service 0711 asset_service asset_service"
|
||||
"mkdir /data/service/el1/public/asset_service 0711 asset_service asset_service",
|
||||
"start asset_service"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
@ -139,8 +139,11 @@ impl_tag_trait! {
|
||||
/// A tag whose value is a byte array indicating the update time of an Asset.
|
||||
OperationType = DataType::Number as isize | 0x46,
|
||||
|
||||
/// A tag whose value is a bool indicating whether the attributes of an asset are required to be encrypted.
|
||||
RequireAttrEncrypted = DataType::Bool as isize | 0x47,
|
||||
|
||||
/// A tag whose value is a 32-bit unsigned integer indicating the specific user id.
|
||||
UserId = DataType::Number as isize | 0x47,
|
||||
UserId = DataType::Number as isize | 0x100,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,7 @@ const std::vector<uint32_t> ACCESS_CONTROL_TAGS = {
|
||||
SEC_ASSET_TAG_IS_PERSISTENT,
|
||||
SEC_ASSET_TAG_SYNC_TYPE,
|
||||
SEC_ASSET_TAG_REQUIRE_PASSWORD_SET,
|
||||
SEC_ASSET_TAG_REQUIRE_ATTR_ENCRYPTED,
|
||||
SEC_ASSET_TAG_USER_ID
|
||||
};
|
||||
|
||||
@ -139,7 +140,8 @@ const std::unordered_map<uint32_t, const char *> TAG_MAP = {
|
||||
{ SEC_ASSET_TAG_RETURN_ORDERED_BY, "RETURN_ORDERED_BY" },
|
||||
{ SEC_ASSET_TAG_UPDATE_TIME, "UPDATE_TIME" },
|
||||
{ SEC_ASSET_TAG_OPERATION_TYPE, "OPERATION_TYPE" },
|
||||
{ SEC_ASSET_TAG_USER_ID, "USER_ID" }
|
||||
{ SEC_ASSET_TAG_REQUIRE_ATTR_ENCRYPTED, "REQUIRE_ATTR_ENCRYPTED" },
|
||||
{ SEC_ASSET_TAG_USER_ID, "USER_ID" },
|
||||
};
|
||||
|
||||
bool CheckAssetRequiredTag(const napi_env env, const std::vector<AssetAttr> &attrs,
|
||||
|
@ -72,6 +72,7 @@ napi_value DeclareTag(const napi_env env)
|
||||
AddUint32Property(env, tag, "RETURN_ORDERED_BY", SEC_ASSET_TAG_RETURN_ORDERED_BY);
|
||||
AddUint32Property(env, tag, "UPDATE_TIME", SEC_ASSET_TAG_UPDATE_TIME);
|
||||
AddUint32Property(env, tag, "OPERATION_TYPE", SEC_ASSET_TAG_OPERATION_TYPE);
|
||||
AddUint32Property(env, tag, "REQUIRE_ATTR_ENCRYPTED", SEC_ASSET_TAG_REQUIRE_ATTR_ENCRYPTED);
|
||||
return tag;
|
||||
}
|
||||
|
||||
|
91
frameworks/os_dependency/file/src/ce_operator.rs
Normal file
91
frameworks/os_dependency/file/src/ce_operator.rs
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//! This file implements ce file operations.
|
||||
|
||||
use asset_definition::{log_throw_error, ErrCode, Result};
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use crate::common::{get_user_dbs, DB_KEY, is_file_exist};
|
||||
|
||||
fn construct_ce_db_dir(user_id: i32) -> String {
|
||||
format!("data/service/el2/{}/asset_service", user_id)
|
||||
}
|
||||
|
||||
fn construct_db_key_cipher_path(user_id: i32) -> String {
|
||||
format!("data/service/el2/{}/asset_service/{}", user_id, DB_KEY)
|
||||
}
|
||||
|
||||
/// Check db key cipher file exists.
|
||||
pub fn is_db_key_cipher_file_exist(user_id: i32) -> Result<bool> {
|
||||
let path_str = construct_db_key_cipher_path(user_id);
|
||||
is_file_exist(&path_str)
|
||||
}
|
||||
|
||||
/// Read db key cipher.
|
||||
pub fn read_db_key_cipher(user_id: i32) -> Result<Vec<u8>> {
|
||||
let path_str = construct_db_key_cipher_path(user_id);
|
||||
let path: &Path = Path::new(&path_str);
|
||||
match fs::read(path) {
|
||||
Ok(db_key_cipher) => Ok(db_key_cipher),
|
||||
Err(e) => {
|
||||
log_throw_error!(
|
||||
ErrCode::FileOperationError,
|
||||
"[FATAL][SA]Read database key ciphertext failed! error is [{}]",
|
||||
e
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Write db key cipher. If path does not exist, create it automatically.
|
||||
pub fn write_db_key_cipher(user_id: i32, db_key_cipher: &Vec<u8>) -> Result<()> {
|
||||
let path_str = construct_db_key_cipher_path(user_id);
|
||||
let path: &Path = Path::new(&path_str);
|
||||
match fs::write(path, db_key_cipher) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => {
|
||||
log_throw_error!(
|
||||
ErrCode::FileOperationError,
|
||||
"[FATAL][SA]Write database key ciphertext failed! error is [{}]",
|
||||
e
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove all CE file in a specific user space.
|
||||
pub fn remove_ce_files(user_id: i32) -> Result<()> {
|
||||
let path_str = construct_ce_db_dir(user_id);
|
||||
for file in fs::read_dir(path_str)? {
|
||||
let file = &file?;
|
||||
match fs::remove_file(file.path().to_string_lossy().to_string()) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
return log_throw_error!(
|
||||
ErrCode::FileOperationError,
|
||||
"[FATAL]Remove [{}] failed, error code:[{}]", file.path().to_string_lossy().to_string(),
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Obtain ce user dbs
|
||||
pub fn get_ce_user_dbs(user_id: i32) -> Result<Vec<String>> {
|
||||
get_user_dbs(&construct_ce_db_dir(user_id))
|
||||
}
|
59
frameworks/os_dependency/file/src/common.rs
Normal file
59
frameworks/os_dependency/file/src/common.rs
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//! This file implements ce file operations.
|
||||
|
||||
use asset_definition::{log_throw_error, Result, ErrCode};
|
||||
use std::{fs, path::Path};
|
||||
|
||||
/// Suffix for backup database files.
|
||||
pub const BACKUP_SUFFIX: &str = ".backup";
|
||||
/// Suffix for database files.
|
||||
pub const DB_SUFFIX: &str = ".db";
|
||||
/// Name for data base key ciphertext file.
|
||||
pub const DB_KEY: &str = "db_key";
|
||||
/// Root path to de user directories.
|
||||
pub const DE_ROOT_PATH: &str = "data/service/el1/public/asset_service";
|
||||
/// Root path to ce user directories.
|
||||
pub const CE_ROOT_PATH: &str = "data/service/el2";
|
||||
|
||||
/// Get all db name in user directory.
|
||||
pub(crate) fn get_user_dbs(path_str: &str) -> Result<Vec<String>> {
|
||||
let mut dbs = vec![];
|
||||
for db_path in fs::read_dir(path_str)? {
|
||||
let db_path = db_path?;
|
||||
let db_file_name = db_path.file_name().to_string_lossy().to_string();
|
||||
if db_file_name.ends_with(DB_SUFFIX) {
|
||||
dbs.push(db_file_name.strip_suffix(DB_SUFFIX).unwrap_or(&db_file_name).to_string())
|
||||
}
|
||||
}
|
||||
Ok(dbs)
|
||||
}
|
||||
|
||||
/// Check whether file exists.
|
||||
pub fn is_file_exist(path_str: &str) -> Result<bool> {
|
||||
let path: &Path = Path::new(&path_str);
|
||||
match path.try_exists() {
|
||||
Ok(true) => Ok(true),
|
||||
Ok(false) => Ok(false),
|
||||
Err(e) => {
|
||||
log_throw_error!(
|
||||
ErrCode::FileOperationError,
|
||||
"[FATAL][SA]]Checking existence of database key ciphertext file failed! error is [{}]",
|
||||
e
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
79
frameworks/os_dependency/file/src/de_operator.rs
Normal file
79
frameworks/os_dependency/file/src/de_operator.rs
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//! This file implements de file operations.
|
||||
|
||||
use asset_definition::{log_throw_error, ErrCode, Result};
|
||||
use asset_log::logi;
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use crate::common::{get_user_dbs, is_file_exist};
|
||||
|
||||
fn construct_user_de_path(user_id: i32) -> String {
|
||||
format!("data/service/el1/public/asset_service/{}", user_id)
|
||||
}
|
||||
|
||||
fn is_user_de_dir_exist(user_id: i32) -> Result<bool> {
|
||||
let path_str = construct_user_de_path(user_id);
|
||||
is_file_exist(&path_str)
|
||||
}
|
||||
|
||||
/// Create user de directory.
|
||||
pub fn create_user_de_dir(user_id: i32) -> Result<()> {
|
||||
if is_user_de_dir_exist(user_id)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
logi!("[INFO]User DE directory does not exist, create it...");
|
||||
let path_str = construct_user_de_path(user_id);
|
||||
let path: &Path = Path::new(&path_str);
|
||||
match fs::create_dir(path) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => Ok(()),
|
||||
Err(e) => {
|
||||
log_throw_error!(
|
||||
ErrCode::FileOperationError,
|
||||
"[FATAL][SA]Create user DE directory failed! error is [{}]",
|
||||
e
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete user de directory.
|
||||
pub fn delete_user_de_dir(user_id: i32) -> Result<()> {
|
||||
if !is_user_de_dir_exist(user_id)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let path_str = construct_user_de_path(user_id);
|
||||
let path: &Path = Path::new(&path_str);
|
||||
match fs::remove_dir_all(path) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) if e.kind() != std::io::ErrorKind::NotFound => Ok(()),
|
||||
Err(e) => {
|
||||
log_throw_error!(
|
||||
ErrCode::FileOperationError,
|
||||
"[FATAL][SA]Delete user DE directory failed! error is [{}]",
|
||||
e
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain de user dbs
|
||||
pub fn get_de_user_dbs(user_id: i32) -> Result<Vec<String>> {
|
||||
get_user_dbs(&construct_user_de_path(user_id))
|
||||
}
|
@ -13,57 +13,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//! This file implement the file operations.
|
||||
//! This file implements file operations.
|
||||
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use asset_definition::{log_throw_error, ErrCode, Result};
|
||||
use asset_log::logi;
|
||||
|
||||
const ROOT_PATH: &str = "data/service/el1/public/asset_service";
|
||||
|
||||
fn construct_user_path(user_id: i32) -> String {
|
||||
format!("{}/{}", ROOT_PATH, user_id)
|
||||
}
|
||||
|
||||
/// Check user db dir exist.
|
||||
pub fn is_user_db_dir_exist(user_id: i32) -> bool {
|
||||
let path_str = construct_user_path(user_id);
|
||||
let path: &Path = Path::new(&path_str);
|
||||
path.exists()
|
||||
}
|
||||
|
||||
/// Create user database directory.
|
||||
pub fn create_user_db_dir(user_id: i32) -> Result<()> {
|
||||
if is_user_db_dir_exist(user_id) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
logi!("[INFO]Directory is not exist, create it...");
|
||||
let path_str = construct_user_path(user_id);
|
||||
let path: &Path = Path::new(&path_str);
|
||||
match fs::create_dir(path) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => Ok(()),
|
||||
Err(e) => {
|
||||
log_throw_error!(ErrCode::FileOperationError, "[FATAL][SA]Create dir failed! error is [{}]", e)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete user database directory.
|
||||
pub fn delete_user_db_dir(user_id: i32) -> Result<()> {
|
||||
if !is_user_db_dir_exist(user_id) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let path_str = construct_user_path(user_id);
|
||||
let path: &Path = Path::new(&path_str);
|
||||
match fs::remove_dir_all(path) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) if e.kind() != std::io::ErrorKind::NotFound => Ok(()),
|
||||
Err(e) => {
|
||||
log_throw_error!(ErrCode::FileOperationError, "[FATAL][SA]Delete dir failed! error is [{}]", e)
|
||||
},
|
||||
}
|
||||
}
|
||||
pub mod ce_operator;
|
||||
pub mod de_operator;
|
||||
pub mod common;
|
@ -175,13 +175,17 @@ typedef enum {
|
||||
*/
|
||||
SEC_ASSET_TAG_UPDATE_TIME = SEC_ASSET_TYPE_BYTES | 0x45,
|
||||
/**
|
||||
* Tag used to store specific user id. The value is of the uint32 type.
|
||||
* A tag whose value is the uint32 type indicating the additional action.
|
||||
*/
|
||||
SEC_ASSET_TAG_OPERATION_TYPE = SEC_ASSET_TYPE_NUMBER | 0x46,
|
||||
/**
|
||||
* A tag whose value is a bool indicating whether the attributes of an asset are required to be encrypted.
|
||||
*/
|
||||
SEC_ASSET_TAG_REQUIRE_ATTR_ENCRYPTED = SEC_ASSET_TYPE_BOOL | 0x47,
|
||||
/**
|
||||
* Tag used to store specific user id. The value is of the uint32 type.
|
||||
*/
|
||||
SEC_ASSET_TAG_USER_ID = SEC_ASSET_TYPE_NUMBER | 0x47,
|
||||
SEC_ASSET_TAG_USER_ID = SEC_ASSET_TYPE_NUMBER | 0x100,
|
||||
} AssetTag;
|
||||
|
||||
/**
|
||||
|
@ -58,10 +58,10 @@ pub const PARAM_NAME_BUNDLE_NAME: &str = "BundleName";
|
||||
/// param name for user id
|
||||
pub const PARAM_NAME_USER_ID: &str = "UserId";
|
||||
|
||||
/// param name for user id
|
||||
/// param name for app index
|
||||
pub const PARAM_NAME_APP_INDEX: &str = "AppIndex";
|
||||
|
||||
/// param name for whether is hap
|
||||
/// param name for owner type
|
||||
pub const PARAM_NAME_IS_HAP: &str = "IsHap";
|
||||
|
||||
/// An enumeration representing different plugin types.
|
||||
@ -78,36 +78,48 @@ pub trait IAssetPluginCtx: Any + Sync + Send + std::panic::RefUnwindSafe {
|
||||
/// Initializes the plugin before usage.
|
||||
fn init(&mut self, user_id: i32) -> Result<(), u32>;
|
||||
|
||||
/// Adds an asset to the database.
|
||||
/// Adds an asset to de db.
|
||||
fn add(&mut self, attributes: &ExtDbMap) -> Result<i32, u32>;
|
||||
|
||||
/// Add an asset with replace.
|
||||
/// Adds an asset to ce cb.
|
||||
fn ce_add(&mut self, attributes: &ExtDbMap) -> Result<i32, u32>;
|
||||
|
||||
/// Adds an asset with replace to de db.
|
||||
fn replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32>;
|
||||
|
||||
/// Queries the asset database.
|
||||
/// Adds an asset with replace to ce db.
|
||||
fn ce_replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32>;
|
||||
|
||||
/// Queries de db.
|
||||
fn query(&mut self, attributes: &ExtDbMap) -> Result<Vec<ExtDbMap>, u32>;
|
||||
|
||||
/// Removes an asset from the database.
|
||||
/// Queries ce db.
|
||||
fn ce_query(&mut self, attributes: &ExtDbMap) -> Result<Vec<ExtDbMap>, u32>;
|
||||
|
||||
/// Removes an asset from de db.
|
||||
fn remove(&mut self, attributes: &ExtDbMap) -> Result<i32, u32>;
|
||||
|
||||
/// Removes assets from the database with specific condition.
|
||||
/// Removes an asset from ce db.
|
||||
fn ce_remove(&mut self, attributes: &ExtDbMap) -> Result<i32, u32>;
|
||||
|
||||
/// Removes assets from de db with specific condition.
|
||||
fn remove_with_specific_cond(&mut self, specific_cond: &str, condition_value: &[Value]) -> Result<i32, u32>;
|
||||
|
||||
/// Updates the attributes of an asset in the database.
|
||||
/// Removes assets from ce db with specific condition.
|
||||
fn ce_remove_with_specific_cond(&mut self, specific_cond: &str, condition_value: &[Value]) -> Result<i32, u32>;
|
||||
|
||||
/// Updates the attributes of an asset in de db.
|
||||
fn update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> Result<i32, u32>;
|
||||
|
||||
/// Begins a transaction for the asset database.
|
||||
fn begin_transaction(&mut self) -> Result<(), u32>;
|
||||
/// Updates the attributes of an asset in ce db.
|
||||
fn ce_update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> Result<i32, u32>;
|
||||
|
||||
/// Commits a transaction for the asset database.
|
||||
fn commit_transaction(&mut self) -> Result<(), u32>;
|
||||
|
||||
/// Rolls back a transaction for the asset database.
|
||||
fn rollback_transaction(&mut self) -> Result<(), u32>;
|
||||
|
||||
/// Returns the storage path for the asset database.
|
||||
/// Returns the storage path for de db.
|
||||
fn get_storage_path(&self) -> String;
|
||||
|
||||
/// Returns the storage path for ce db.
|
||||
fn ce_get_storage_path(&self) -> String;
|
||||
|
||||
/// Increase count
|
||||
fn increase_count(&mut self);
|
||||
|
||||
|
@ -34,6 +34,11 @@ impl CallingInfo {
|
||||
Self::new(0, OwnerType::Native, "asset_service_8100".as_bytes().to_vec())
|
||||
}
|
||||
|
||||
/// Build identity of part process info.
|
||||
pub fn new_part_info(user_id: i32) -> Self {
|
||||
Self::new(user_id, OwnerType::Native, "asset_service_8100".as_bytes().to_vec())
|
||||
}
|
||||
|
||||
/// Build identity of the specified owner.
|
||||
pub fn new(user_id: i32, owner_type: OwnerType, owner_info: Vec<u8>) -> Self {
|
||||
Self { user_id, owner_type, owner_info }
|
||||
@ -67,6 +72,11 @@ impl CallingInfo {
|
||||
self.owner_type as u32
|
||||
}
|
||||
|
||||
/// Get owner type enum of calling.
|
||||
pub fn owner_type_enum(&self) -> OwnerType {
|
||||
self.owner_type
|
||||
}
|
||||
|
||||
/// Get owner info of calling.
|
||||
pub fn owner_info(&self) -> &Vec<u8> {
|
||||
&self.owner_info
|
||||
|
@ -25,6 +25,7 @@ ohos_rust_shared_library("asset_service") {
|
||||
"../../interfaces/inner_api/rs:asset_sdk_rust",
|
||||
"../common:asset_common",
|
||||
"../crypto_manager:asset_crypto_manager",
|
||||
"../db_key_operator:asset_db_key_operator",
|
||||
"../db_operator:asset_db_operator",
|
||||
"../os_dependency:asset_os_dependency",
|
||||
"../plugin:asset_plugin",
|
||||
|
@ -24,10 +24,11 @@ samgr = { git = "https://gitee.com/openharmony/systemabilitymgr_samgr.git" }
|
||||
system_ability_fwk = { git = "https://gitee.com/openharmony/systemabilitymgr_safwk" }
|
||||
hisysevent = { git = "https://gitee.com/openharmony/hiviewdfx_hisysevent.git" }
|
||||
ipc = { git = "https://gitee.com/openharmony/communication_ipc" }
|
||||
ylong_runtime = { git = "https://gitee.com/openharmony/commonlibrary_rust_ylong_runtime.git", features = ["full"]}
|
||||
ylong_runtime = { git = "https://gitee.com/openharmony/commonlibrary_rust_ylong_runtime.git", features = ["full"] }
|
||||
|
||||
asset_common = { path = "../common" }
|
||||
asset_crypto_manager = { path = "../crypto_manager" }
|
||||
asset_db_key_operator = { path = "../db_key_operator" }
|
||||
asset_db_operator = { path = "../db_operator" }
|
||||
asset_definition = { path = "../../frameworks/definition" }
|
||||
asset_file_operator = { path = "../../frameworks/os_dependency/file" }
|
||||
|
@ -25,12 +25,13 @@ use std::{
|
||||
use asset_common::{AutoCounter, CallingInfo, OwnerType};
|
||||
use asset_crypto_manager::{crypto_manager::CryptoManager, secret_key::SecretKey};
|
||||
use asset_db_operator::{
|
||||
database::Database,
|
||||
types::{column, DbMap},
|
||||
database::Database, database_file_upgrade::construct_splited_db_name, types::{column, DbMap}
|
||||
};
|
||||
use asset_definition::{Result, SyncType, Value};
|
||||
use asset_file_operator::delete_user_db_dir;
|
||||
use asset_log::{loge, logi};
|
||||
use asset_definition::{log_throw_error, ErrCode, Result, SyncType, Value};
|
||||
use asset_file_operator::{
|
||||
ce_operator::is_db_key_cipher_file_exist, common::{BACKUP_SUFFIX, CE_ROOT_PATH, DB_SUFFIX, DE_ROOT_PATH}, de_operator::delete_user_de_dir
|
||||
};
|
||||
use asset_log::{loge, logi, logw};
|
||||
use asset_plugin::asset_plugin::AssetPlugin;
|
||||
use asset_sdk::plugin_interface::{
|
||||
EventType, ExtDbMap, PARAM_NAME_APP_INDEX, PARAM_NAME_BUNDLE_NAME, PARAM_NAME_IS_HAP, PARAM_NAME_USER_ID,
|
||||
@ -38,22 +39,79 @@ use asset_sdk::plugin_interface::{
|
||||
|
||||
use crate::sys_event::upload_fault_system_event;
|
||||
|
||||
const ASSET_DB: &str = "asset.db";
|
||||
const BACKUP_SUFFIX: &str = ".backup";
|
||||
const ROOT_PATH: &str = "data/service/el1/public/asset_service";
|
||||
/// success code.
|
||||
const SUCCESS: i32 = 0;
|
||||
const USER_ID_VEC_BUFFER: u32 = 5;
|
||||
const MINIMUM_MAIN_USER_ID: i32 = 100;
|
||||
|
||||
fn delete_on_package_removed(user_id: i32, owner: Vec<u8>) -> Result<bool> {
|
||||
let mut cond = DbMap::new();
|
||||
cond.insert(column::OWNER_TYPE, Value::Number(OwnerType::Hap as u32));
|
||||
cond.insert(column::OWNER, Value::Bytes(owner));
|
||||
cond.insert(column::IS_PERSISTENT, Value::Bool(false));
|
||||
fn remove_db(file_path: &str, calling_info: &CallingInfo, is_ce: bool) -> Result<()> {
|
||||
let db_name = construct_splited_db_name(calling_info.owner_type_enum(), calling_info.owner_info(), is_ce)?;
|
||||
for db_path in fs::read_dir(file_path)? {
|
||||
let db_path = db_path?;
|
||||
let db_file_name = db_path.file_name().to_string_lossy().to_string();
|
||||
if db_file_name.contains(&db_name) {
|
||||
match fs::remove_file(&db_path.path().to_string_lossy().to_string()) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
logw!("[WARNING]Remove db:[{}] failed, error code:[{}]", db_file_name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete_in_de_db_on_package_removed(
|
||||
calling_info: &CallingInfo,
|
||||
delete_cond: &DbMap,
|
||||
reverse_condition: &DbMap,
|
||||
check_cond: &DbMap
|
||||
) -> Result<bool> {
|
||||
// Delete non-persistent data in de db.
|
||||
let mut de_db = Database::build(calling_info, false)?;
|
||||
let _ = de_db.delete_datas(delete_cond, Some(reverse_condition), false)?;
|
||||
let de_db_data_exists = de_db.is_data_exists(check_cond, false)?;
|
||||
// remove db and backup db
|
||||
if !de_db_data_exists {
|
||||
remove_db(&format!("{}/{}", DE_ROOT_PATH,calling_info.user_id()), calling_info, false)?;
|
||||
}
|
||||
Ok(de_db_data_exists)
|
||||
}
|
||||
|
||||
fn delete_in_ce_db_on_package_removed(
|
||||
calling_info: &CallingInfo,
|
||||
delete_cond: &DbMap,
|
||||
reverse_condition: &DbMap,
|
||||
check_cond: &DbMap,
|
||||
) -> Result<bool> {
|
||||
// Delete non-persistent data in ce db if ce db file exists.
|
||||
let mut ce_db = Database::build(calling_info, true)?;
|
||||
let _ = ce_db.delete_datas(delete_cond, Some(reverse_condition), false)?;
|
||||
// Check whether there is still persistent data left in ce db.
|
||||
let ce_db_data_exists = ce_db.is_data_exists(check_cond, false)?;
|
||||
if !ce_db_data_exists {
|
||||
remove_db(&format!("{}/{}/asset_service", CE_ROOT_PATH, calling_info.user_id()), calling_info, false)?;
|
||||
}
|
||||
Ok(ce_db_data_exists)
|
||||
}
|
||||
|
||||
fn delete_on_package_removed(owner: Vec<u8>, calling_info: &CallingInfo) -> Result<bool> {
|
||||
let mut delete_cond = DbMap::new();
|
||||
delete_cond.insert(column::OWNER_TYPE, Value::Number(OwnerType::Hap as u32));
|
||||
delete_cond.insert(column::OWNER, Value::Bytes(owner.clone()));
|
||||
delete_cond.insert(column::IS_PERSISTENT, Value::Bool(false));
|
||||
let mut reverse_condition = DbMap::new();
|
||||
reverse_condition.insert(column::SYNC_TYPE, Value::Number(SyncType::TrustedAccount as u32));
|
||||
let mut db = Database::build(user_id)?;
|
||||
let _ = db.delete_datas(&cond, Some(&reverse_condition), false)?;
|
||||
let mut check_cond = delete_cond.clone();
|
||||
check_cond.remove(column::IS_PERSISTENT);
|
||||
let de_db_data_exists = delete_in_de_db_on_package_removed(calling_info, &delete_cond, &reverse_condition, &check_cond)?;
|
||||
|
||||
cond.remove(column::IS_PERSISTENT);
|
||||
db.is_data_exists(&cond, false)
|
||||
if is_db_key_cipher_file_exist(calling_info.user_id())? {
|
||||
let ce_db_data_exists = delete_in_ce_db_on_package_removed(calling_info, &delete_cond, &reverse_condition, &check_cond)?;
|
||||
Ok(de_db_data_exists || ce_db_data_exists)
|
||||
} else {
|
||||
Ok(de_db_data_exists)
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_cryptos(calling_info: &CallingInfo) {
|
||||
@ -67,7 +125,7 @@ fn delete_data_by_owner(user_id: i32, owner: *const u8, owner_size: u32) {
|
||||
let owner: Vec<u8> = unsafe { slice::from_raw_parts(owner, owner_size as usize).to_vec() };
|
||||
let calling_info = CallingInfo::new(user_id, OwnerType::Hap, owner.clone());
|
||||
clear_cryptos(&calling_info);
|
||||
let res = match delete_on_package_removed(user_id, owner) {
|
||||
let res = match delete_on_package_removed(owner, &calling_info) {
|
||||
Ok(true) => {
|
||||
logi!("The owner wants to retain data after uninstallation. Do not delete key in HUKS!");
|
||||
Ok(())
|
||||
@ -76,10 +134,9 @@ fn delete_data_by_owner(user_id: i32, owner: *const u8, owner_size: u32) {
|
||||
Err(e) => {
|
||||
// Report the database operation fault event.
|
||||
upload_fault_system_event(&calling_info, start_time, "on_package_removed", &e);
|
||||
SecretKey::delete_by_owner(&calling_info)
|
||||
Ok(())
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(e) = res {
|
||||
// Report the key operation fault event.
|
||||
let calling_info = CallingInfo::new_self();
|
||||
@ -124,7 +181,7 @@ pub(crate) extern "C" fn on_package_removed(
|
||||
|
||||
extern "C" fn delete_dir_by_user(user_id: i32) {
|
||||
let _counter_user = AutoCounter::new();
|
||||
let _ = delete_user_db_dir(user_id);
|
||||
let _ = delete_user_de_dir(user_id);
|
||||
}
|
||||
|
||||
extern "C" fn delete_crypto_need_unlock() {
|
||||
@ -197,24 +254,86 @@ pub(crate) extern "C" fn on_schedule_wakeup() {
|
||||
}
|
||||
}
|
||||
|
||||
fn backup_db_if_accessible(entry: &DirEntry, user_id: i32) -> Result<()> {
|
||||
let from_path = entry.path().with_file_name(format!("{}/{}", user_id, ASSET_DB)).to_string_lossy().to_string();
|
||||
Database::check_db_accessible(from_path.clone(), user_id)?;
|
||||
let backup_path = format!("{}{}", from_path, BACKUP_SUFFIX);
|
||||
fs::copy(from_path, backup_path)?;
|
||||
fn backup_de_db_if_accessible(entry: &DirEntry, user_id: i32) -> Result<()> {
|
||||
for db_path in fs::read_dir(format!("{}", entry.path().to_string_lossy()))? {
|
||||
let db_path = db_path?;
|
||||
let db_name = db_path.file_name().to_string_lossy().to_string();
|
||||
if db_name.ends_with(DB_SUFFIX) {
|
||||
let from_path = db_path.path().to_string_lossy().to_string();
|
||||
Database::check_de_db_accessible(from_path.clone(), user_id, db_name.clone())?;
|
||||
let backup_path = format!("{}{}", from_path, BACKUP_SUFFIX);
|
||||
fs::copy(from_path, backup_path)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn backup_ce_db(user_id: i32) -> Result<()> {
|
||||
if user_id < MINIMUM_MAIN_USER_ID {
|
||||
return Ok(());
|
||||
}
|
||||
let ce_path = format!("{}/{}/asset_service", CE_ROOT_PATH, user_id);
|
||||
for db_path in fs::read_dir(ce_path)? {
|
||||
let db_path = db_path?;
|
||||
let db_name = db_path.file_name().to_string_lossy().to_string();
|
||||
if db_name.ends_with(DB_SUFFIX) {
|
||||
let from_path = db_path.path().to_string_lossy().to_string();
|
||||
let backup_path = format!("{}{}", from_path, BACKUP_SUFFIX);
|
||||
fs::copy(from_path, backup_path)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn GetUserIds(userIdsPtr: *mut i32, userIdsSize: *mut u32) -> i32;
|
||||
fn GetUsersSize(userIdsSize: *mut u32) -> i32;
|
||||
}
|
||||
|
||||
fn backup_all_db(start_time: &Instant) -> Result<()> {
|
||||
for entry in fs::read_dir(ROOT_PATH)? {
|
||||
// Backup all de db if accessible.
|
||||
for entry in fs::read_dir(DE_ROOT_PATH)? {
|
||||
let entry = entry?;
|
||||
if let Ok(user_id) = entry.file_name().to_string_lossy().to_string().parse::<i32>() {
|
||||
if let Err(e) = backup_db_if_accessible(&entry, user_id) {
|
||||
if let Err(e) = backup_de_db_if_accessible(&entry, user_id) {
|
||||
let calling_info = CallingInfo::new_self();
|
||||
upload_fault_system_event(&calling_info, *start_time, &format!("backup_db_{}", user_id), &e);
|
||||
upload_fault_system_event(&calling_info, *start_time, &format!("backup_de_db_{}", user_id), &e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Backup all ce db if db key cipher file exists.
|
||||
let mut user_ids_size: u32 = 0;
|
||||
let user_ids_size_ptr = &mut user_ids_size;
|
||||
let mut ret: i32;
|
||||
unsafe {
|
||||
ret = GetUsersSize(user_ids_size_ptr);
|
||||
}
|
||||
if ret != SUCCESS {
|
||||
return log_throw_error!(ErrCode::AccountError, "[FATAL][SA]Get users size failed.");
|
||||
}
|
||||
|
||||
let mut user_ids: Vec<i32> = vec![0i32; (*user_ids_size_ptr + USER_ID_VEC_BUFFER).try_into().unwrap()];
|
||||
let user_ids_ptr = user_ids.as_mut_ptr();
|
||||
unsafe {
|
||||
ret = GetUserIds(user_ids_ptr, user_ids_size_ptr);
|
||||
}
|
||||
if ret != SUCCESS {
|
||||
return log_throw_error!(ErrCode::AccountError, "[FATAL][SA]Get user IDs failed.");
|
||||
}
|
||||
|
||||
let user_ids_slice;
|
||||
unsafe {
|
||||
user_ids_slice = slice::from_raw_parts_mut(user_ids_ptr, (*user_ids_size_ptr).try_into().unwrap());
|
||||
}
|
||||
for user_id in user_ids_slice.iter() {
|
||||
if let Err(e) = backup_ce_db(*user_id) {
|
||||
let calling_info = CallingInfo::new_self();
|
||||
upload_fault_system_event(&calling_info, *start_time, &format!("backup_ce_db_{}", *user_id), &e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use asset_file_operator::delete_user_db_dir;
|
||||
use asset_file_operator::de_operator::delete_user_de_dir;
|
||||
use asset_log::{loge, logi};
|
||||
use system_ability_fwk::cxx_share::SystemAbilityOnDemandReason;
|
||||
|
||||
@ -82,7 +82,7 @@ pub(crate) fn handle_common_event(reason: SystemAbilityOnDemandReason) {
|
||||
handle_package_removed(&want, true);
|
||||
} else if reason_name == "usual.event.USER_REMOVED" {
|
||||
logi!("on_start by user remove");
|
||||
let _ = delete_user_db_dir(reason.extra_data.code);
|
||||
let _ = delete_user_de_dir(reason.extra_data.code);
|
||||
} else if reason_name == "usual.event.CHARGING" {
|
||||
listener::backup_db();
|
||||
} else if reason_name == "COMMON_EVENT_RESTORE_START" {
|
||||
|
@ -15,8 +15,9 @@
|
||||
|
||||
//! This module implements the Asset service.
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{fs, time::{Duration, Instant}};
|
||||
|
||||
use asset_db_operator::database_file_upgrade::check_and_split_db;
|
||||
use samgr::manage::SystemAbilityManager;
|
||||
use system_ability_fwk::{
|
||||
ability::{Ability, Handler},
|
||||
@ -24,9 +25,10 @@ use system_ability_fwk::{
|
||||
};
|
||||
use ylong_runtime::{builder::RuntimeBuilder, time::sleep};
|
||||
|
||||
use asset_common::{CallingInfo, Counter};
|
||||
use asset_common::{AutoCounter, CallingInfo, Counter, OwnerType};
|
||||
use asset_crypto_manager::crypto_manager::CryptoManager;
|
||||
use asset_definition::{log_throw_error, AssetMap, ErrCode, Result};
|
||||
use asset_file_operator::{common::DE_ROOT_PATH, de_operator::create_user_de_dir};
|
||||
use asset_ipc::SA_ID;
|
||||
use asset_log::{loge, logi};
|
||||
use asset_plugin::asset_plugin::{AssetContext, AssetPlugin};
|
||||
@ -102,11 +104,22 @@ impl Ability for AssetAbility {
|
||||
}
|
||||
}
|
||||
|
||||
async fn upgrade_process() -> Result<()> {
|
||||
let _counter_user = AutoCounter::new();
|
||||
for entry in fs::read_dir(DE_ROOT_PATH)? {
|
||||
let entry = entry?;
|
||||
if let Ok(user_id) = entry.file_name().to_string_lossy().parse::<i32>() {
|
||||
check_and_split_db(user_id)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_service(handler: Handler) -> Result<()> {
|
||||
let asset_plugin = AssetPlugin::get_instance();
|
||||
match asset_plugin.load_plugin() {
|
||||
Ok(loader) => {
|
||||
let _tr = loader.init(Box::new(AssetContext { data_base: None }));
|
||||
let _tr = loader.init(Box::new(AssetContext { user_id: 0, calling_info: CallingInfo::new(0, OwnerType::Hap, vec![]) }));
|
||||
logi!("load plugin success.");
|
||||
},
|
||||
Err(_) => loge!("load plugin failed."),
|
||||
@ -116,6 +129,7 @@ fn start_service(handler: Handler) -> Result<()> {
|
||||
if !handler.publish(AssetService::new(handler.clone())) {
|
||||
return log_throw_error!(ErrCode::IpcError, "Asset publish stub object failed");
|
||||
};
|
||||
let _handle = ylong_runtime::spawn(upgrade_process());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -142,8 +156,8 @@ macro_rules! execute {
|
||||
let func_name = hisysevent::function!();
|
||||
let start = Instant::now();
|
||||
let _trace = TraceScope::trace(func_name);
|
||||
// Create database directory if not exists.
|
||||
asset_file_operator::create_user_db_dir($calling_info.user_id())?;
|
||||
// Create de database directory if not exists.
|
||||
create_user_de_dir($calling_info.user_id())?;
|
||||
upload_system_event($func($calling_info, $($args),+), $calling_info, start, func_name)
|
||||
}};
|
||||
}
|
||||
|
@ -29,7 +29,9 @@ use asset_definition::{
|
||||
};
|
||||
use asset_log::{loge, logi};
|
||||
use asset_plugin::asset_plugin::AssetPlugin;
|
||||
use asset_sdk::plugin_interface::{EventType, ExtDbMap, PARAM_NAME_BUNDLE_NAME, PARAM_NAME_USER_ID};
|
||||
use asset_sdk::plugin_interface::{
|
||||
EventType, ExtDbMap, PARAM_NAME_BUNDLE_NAME, PARAM_NAME_USER_ID,
|
||||
};
|
||||
|
||||
const TAG_COLUMN_TABLE: [(Tag, &str); 20] = [
|
||||
(Tag::Secret, column::SECRET),
|
||||
@ -80,13 +82,14 @@ pub(crate) const NORMAL_LABEL_ATTRS: [Tag; 4] =
|
||||
pub(crate) const NORMAL_LOCAL_LABEL_ATTRS: [Tag; 4] =
|
||||
[Tag::DataLabelNormalLocal1, Tag::DataLabelNormalLocal2, Tag::DataLabelNormalLocal3, Tag::DataLabelNormalLocal4];
|
||||
|
||||
pub(crate) const ACCESS_CONTROL_ATTRS: [Tag; 7] = [
|
||||
pub(crate) const ACCESS_CONTROL_ATTRS: [Tag; 8] = [
|
||||
Tag::Alias,
|
||||
Tag::Accessibility,
|
||||
Tag::AuthType,
|
||||
Tag::IsPersistent,
|
||||
Tag::SyncType,
|
||||
Tag::RequirePasswordSet,
|
||||
Tag::RequireAttrEncrypted,
|
||||
Tag::UserId,
|
||||
];
|
||||
|
||||
@ -136,7 +139,7 @@ pub(crate) fn build_secret_key(calling: &CallingInfo, attrs: &DbMap) -> Result<S
|
||||
let auth_type = attrs.get_enum_attr::<AuthType>(&column::AUTH_TYPE)?;
|
||||
let access_type = attrs.get_enum_attr::<Accessibility>(&column::ACCESSIBILITY)?;
|
||||
let require_password_set = attrs.get_bool_attr(&column::REQUIRE_PASSWORD_SET)?;
|
||||
SecretKey::new(calling, auth_type, access_type, require_password_set)
|
||||
SecretKey::new(calling, auth_type, access_type, require_password_set, None)
|
||||
}
|
||||
|
||||
fn build_aad_v1(attrs: &DbMap) -> Vec<u8> {
|
||||
|
@ -146,7 +146,7 @@ fn check_data_value(tag: &Tag, value: &Value) -> Result<()> {
|
||||
Tag::Secret => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_SECRET_SIZE),
|
||||
Tag::Alias => check_array_size(tag, value, MIN_ARRAY_SIZE, MAX_ALIAS_SIZE),
|
||||
Tag::Accessibility => check_enum_variant::<Accessibility>(tag, value),
|
||||
Tag::RequirePasswordSet | Tag::IsPersistent => Ok(()),
|
||||
Tag::RequirePasswordSet | Tag::IsPersistent | Tag::RequireAttrEncrypted => Ok(()),
|
||||
Tag::AuthType => check_enum_variant::<AuthType>(tag, value),
|
||||
Tag::AuthValidityPeriod => check_number_range(tag, value, MIN_NUMBER_VALUE, MAX_AUTH_VALID_PERIOD),
|
||||
Tag::AuthChallenge => check_array_size(tag, value, CHALLENGE_SIZE - 1, CHALLENGE_SIZE),
|
||||
|
@ -15,46 +15,26 @@
|
||||
|
||||
//! This module is used to insert an Asset with a specified alias.
|
||||
|
||||
use std::{ffi::CString, os::raw::c_char, sync::Mutex};
|
||||
use std::{ffi::CString, os::raw::c_char};
|
||||
|
||||
use asset_common::CallingInfo;
|
||||
use asset_crypto_manager::{crypto::Crypto, secret_key::SecretKey};
|
||||
use asset_crypto_manager::crypto::Crypto;
|
||||
use asset_db_key_operator::generate_secret_key_if_needed;
|
||||
use asset_db_operator::{
|
||||
database::Database,
|
||||
database::{create_db_instance, Database},
|
||||
types::{column, DbMap, DB_DATA_VERSION},
|
||||
};
|
||||
use asset_definition::{
|
||||
log_throw_error, Accessibility, AssetMap, AuthType, ConflictResolution, ErrCode, Extension, LocalStatus, Result,
|
||||
SyncStatus, SyncType, Tag, Value,
|
||||
};
|
||||
use asset_log::logi;
|
||||
use asset_utils::time;
|
||||
|
||||
use crate::operations::common;
|
||||
|
||||
static GEN_KEY_MUTEX: Mutex<()> = Mutex::new(());
|
||||
|
||||
fn generate_key_if_needed(secret_key: &SecretKey) -> Result<()> {
|
||||
match secret_key.exists() {
|
||||
Ok(true) => Ok(()),
|
||||
Ok(false) => {
|
||||
let _lock = GEN_KEY_MUTEX.lock().unwrap();
|
||||
match secret_key.exists() {
|
||||
Ok(true) => Ok(()),
|
||||
Ok(false) => {
|
||||
logi!("[INFO]The key does not exist, generate it.");
|
||||
secret_key.generate()
|
||||
},
|
||||
Err(ret) => Err(ret),
|
||||
}
|
||||
},
|
||||
Err(ret) => Err(ret),
|
||||
}
|
||||
}
|
||||
|
||||
fn encrypt(calling_info: &CallingInfo, db_data: &mut DbMap) -> Result<()> {
|
||||
fn encrypt_secret(calling_info: &CallingInfo, db_data: &mut DbMap) -> Result<()> {
|
||||
let secret_key = common::build_secret_key(calling_info, db_data)?;
|
||||
generate_key_if_needed(&secret_key)?;
|
||||
generate_secret_key_if_needed(&secret_key)?;
|
||||
|
||||
let secret = db_data.get_bytes_attr(&column::SECRET)?;
|
||||
let cipher = Crypto::encrypt(&secret_key, secret, &common::build_aad(db_data)?)?;
|
||||
@ -71,7 +51,7 @@ fn resolve_conflict(
|
||||
) -> Result<()> {
|
||||
match attrs.get(&Tag::ConflictResolution) {
|
||||
Some(Value::Number(num)) if *num == ConflictResolution::Overwrite as u32 => {
|
||||
encrypt(calling, db_data)?;
|
||||
encrypt_secret(calling, db_data)?;
|
||||
db.replace_datas(query, false, db_data)
|
||||
},
|
||||
_ => {
|
||||
@ -79,7 +59,7 @@ fn resolve_conflict(
|
||||
condition.insert(column::SYNC_TYPE, Value::Number(SyncType::TrustedAccount as u32));
|
||||
condition.insert(column::SYNC_STATUS, Value::Number(SyncStatus::SyncDel as u32));
|
||||
if db.is_data_exists(&condition, false)? {
|
||||
encrypt(calling, db_data)?;
|
||||
encrypt_secret(calling, db_data)?;
|
||||
db.replace_datas(&condition, false, db_data)
|
||||
} else {
|
||||
log_throw_error!(ErrCode::Duplicated, "[FATAL][SA]The specified alias already exists.")
|
||||
@ -175,14 +155,17 @@ fn local_add(attributes: &AssetMap, calling_info: &CallingInfo) -> Result<()> {
|
||||
add_default_attrs(&mut db_data);
|
||||
|
||||
let query = get_query_condition(calling_info, attributes)?;
|
||||
let mut db = Database::build(calling_info.user_id())?;
|
||||
|
||||
let mut db = create_db_instance(attributes, calling_info)?;
|
||||
|
||||
if db.is_data_exists(&query, false)? {
|
||||
resolve_conflict(calling_info, &mut db, attributes, &query, &mut db_data)
|
||||
resolve_conflict(calling_info, &mut db, attributes, &query, &mut db_data)?;
|
||||
} else {
|
||||
encrypt(calling_info, &mut db_data)?;
|
||||
encrypt_secret(calling_info, &mut db_data)?;
|
||||
let _ = db.insert_datas(&db_data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn add(calling_info: &CallingInfo, attributes: &AssetMap) -> Result<()> {
|
||||
|
@ -17,10 +17,7 @@
|
||||
|
||||
use asset_common::CallingInfo;
|
||||
use asset_crypto_manager::{crypto::Crypto, crypto_manager::CryptoManager, secret_key::SecretKey};
|
||||
use asset_db_operator::{
|
||||
database::Database,
|
||||
types::{column, DbMap},
|
||||
};
|
||||
use asset_db_operator::{database::create_db_instance, types::{column, DbMap}};
|
||||
use asset_definition::{log_throw_error, Accessibility, AssetMap, AuthType, ErrCode, Extension, Result, Tag, Value};
|
||||
|
||||
use crate::operations::common;
|
||||
@ -47,13 +44,9 @@ fn check_arguments(attributes: &AssetMap) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
fn query_key_attrs(calling_info: &CallingInfo, db_data: &DbMap) -> Result<(Accessibility, bool)> {
|
||||
let results = Database::build(calling_info.user_id())?.query_datas(
|
||||
&vec![column::ACCESSIBILITY, column::REQUIRE_PASSWORD_SET],
|
||||
db_data,
|
||||
None,
|
||||
true,
|
||||
)?;
|
||||
fn query_key_attrs(calling_info: &CallingInfo, db_data: &DbMap, attrs: &AssetMap) -> Result<(Accessibility, bool)> {
|
||||
let mut db = create_db_instance(attrs, calling_info)?;
|
||||
let results = db.query_datas(&vec![column::ACCESSIBILITY, column::REQUIRE_PASSWORD_SET], db_data, None, true)?;
|
||||
match results.len() {
|
||||
0 => log_throw_error!(ErrCode::NotFound, "[FATAL][SA]No data that meets the query conditions is found."),
|
||||
1 => {
|
||||
@ -75,12 +68,12 @@ pub(crate) fn pre_query(calling_info: &CallingInfo, query: &AssetMap) -> Result<
|
||||
common::add_owner_info(calling_info, &mut db_data);
|
||||
db_data.entry(column::AUTH_TYPE).or_insert(Value::Number(AuthType::Any as u32));
|
||||
|
||||
let (access_type, require_password_set) = query_key_attrs(calling_info, &db_data)?;
|
||||
let (access_type, require_password_set) = query_key_attrs(calling_info, &db_data, query)?;
|
||||
let valid_time = match query.get(&Tag::AuthValidityPeriod) {
|
||||
Some(Value::Number(num)) => *num,
|
||||
_ => DEFAULT_AUTH_VALIDITY_IN_SECS,
|
||||
};
|
||||
let secret_key = SecretKey::new(calling_info, AuthType::Any, access_type, require_password_set)?;
|
||||
let secret_key = SecretKey::new(calling_info, AuthType::Any, access_type, require_password_set, None)?;
|
||||
let mut crypto = Crypto::build(secret_key, valid_time)?;
|
||||
let challenge = crypto.init_key()?.to_vec();
|
||||
let crypto_manager = CryptoManager::get_instance();
|
||||
|
@ -20,7 +20,7 @@ use std::cmp::Ordering;
|
||||
use asset_common::CallingInfo;
|
||||
use asset_crypto_manager::{crypto::Crypto, crypto_manager::CryptoManager};
|
||||
use asset_db_operator::{
|
||||
database::Database,
|
||||
database::{create_db_instance, Database},
|
||||
types::{column, DbMap, QueryOptions, DB_DATA_VERSION},
|
||||
};
|
||||
use asset_definition::{
|
||||
@ -59,7 +59,7 @@ fn upgrade_version(db: &mut Database, calling_info: &CallingInfo, db_data: &mut
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decrypt(calling_info: &CallingInfo, db_data: &mut DbMap) -> Result<()> {
|
||||
fn decrypt_secret(calling_info: &CallingInfo, db_data: &mut DbMap) -> Result<()> {
|
||||
let secret = db_data.get_bytes_attr(&column::SECRET)?;
|
||||
let secret_key = common::build_secret_key(calling_info, db_data)?;
|
||||
let secret = Crypto::decrypt(&secret_key, secret, &common::build_aad(db_data)?)?;
|
||||
@ -86,7 +86,7 @@ fn exec_crypto(calling_info: &CallingInfo, query: &AssetMap, db_data: &mut DbMap
|
||||
}
|
||||
|
||||
fn query_all(calling_info: &CallingInfo, db_data: &mut DbMap, query: &AssetMap) -> Result<Vec<AssetMap>> {
|
||||
let mut db = Database::build(calling_info.user_id())?;
|
||||
let mut db = create_db_instance(query, calling_info)?;
|
||||
let mut results = db.query_datas(&vec![], db_data, None, true)?;
|
||||
match results.len() {
|
||||
0 => throw_error!(ErrCode::NotFound, "[FATAL]The data to be queried does not exist."),
|
||||
@ -95,7 +95,7 @@ fn query_all(calling_info: &CallingInfo, db_data: &mut DbMap, query: &AssetMap)
|
||||
Some(Value::Number(auth_type)) if *auth_type == AuthType::Any as u32 => {
|
||||
exec_crypto(calling_info, query, &mut results[0])?;
|
||||
},
|
||||
_ => decrypt(calling_info, &mut results[0])?,
|
||||
_ => decrypt_secret(calling_info, &mut results[0])?,
|
||||
};
|
||||
if common::need_upgrade(&results[0])? {
|
||||
upgrade_version(&mut db, calling_info, &mut results[0])?;
|
||||
@ -140,12 +140,8 @@ fn get_query_options(attrs: &AssetMap) -> QueryOptions {
|
||||
}
|
||||
|
||||
pub(crate) fn query_attrs(calling_info: &CallingInfo, db_data: &DbMap, attrs: &AssetMap) -> Result<Vec<AssetMap>> {
|
||||
let mut results = Database::build(calling_info.user_id())?.query_datas(
|
||||
&vec![],
|
||||
db_data,
|
||||
Some(&get_query_options(attrs)),
|
||||
true,
|
||||
)?;
|
||||
let mut db = create_db_instance(attrs, calling_info)?;
|
||||
let mut results = db.query_datas(&vec![], db_data, Some(&get_query_options(attrs)), true)?;
|
||||
if results.is_empty() {
|
||||
return throw_error!(ErrCode::NotFound, "[FATAL]The data to be queried does not exist.");
|
||||
}
|
||||
|
@ -16,10 +16,7 @@
|
||||
//! This module is used to delete the Asset, including single and batch deletion.
|
||||
|
||||
use asset_common::CallingInfo;
|
||||
use asset_db_operator::{
|
||||
database::Database,
|
||||
types::{column, DbMap},
|
||||
};
|
||||
use asset_db_operator::{database::create_db_instance, types::{column, DbMap}};
|
||||
use asset_definition::{log_throw_error, AssetMap, ErrCode, Result, SyncStatus, SyncType, Value};
|
||||
use asset_log::logi;
|
||||
use asset_utils::time;
|
||||
@ -57,7 +54,7 @@ pub(crate) fn remove(calling_info: &CallingInfo, query: &AssetMap) -> Result<()>
|
||||
add_system_attrs(&mut update_db_data)?;
|
||||
add_normal_attrs(&mut update_db_data);
|
||||
|
||||
let mut db = Database::build(calling_info.user_id())?;
|
||||
let mut db = create_db_instance(query, calling_info)?;
|
||||
let results = db.query_datas(&vec![], &db_data, None, true)?;
|
||||
if results.is_empty() {
|
||||
return log_throw_error!(ErrCode::NotFound, "[FATAL]The data to be deleted does not exist.");
|
||||
|
@ -17,10 +17,7 @@
|
||||
|
||||
use asset_common::CallingInfo;
|
||||
use asset_crypto_manager::crypto::Crypto;
|
||||
use asset_db_operator::{
|
||||
database::Database,
|
||||
types::{column, DbMap, DB_DATA_VERSION},
|
||||
};
|
||||
use asset_db_operator::{database::create_db_instance, types::{column, DbMap, DB_DATA_VERSION}};
|
||||
use asset_definition::{log_throw_error, AssetMap, ErrCode, Extension, LocalStatus, Result, SyncStatus, Tag, Value};
|
||||
use asset_utils::time;
|
||||
|
||||
@ -97,7 +94,7 @@ pub(crate) fn update(calling_info: &CallingInfo, query: &AssetMap, update: &Asse
|
||||
add_system_attrs(update, &mut update_db_data)?;
|
||||
add_normal_attrs(&mut update_db_data);
|
||||
|
||||
let mut db = Database::build(calling_info.user_id())?;
|
||||
let mut db = create_db_instance(query, calling_info)?;
|
||||
let results = db.query_datas(&vec![], &query_db_data, None, true)?;
|
||||
if results.is_empty() {
|
||||
return log_throw_error!(ErrCode::NotFound, "[FATAL]The asset to update is not found.");
|
||||
|
@ -97,8 +97,7 @@ pub(crate) fn upload_fault_system_event(
|
||||
.set_param(build_str_param!(SysEvent::EXTRA, e.msg.clone()))
|
||||
.write();
|
||||
loge!(
|
||||
"[ERROR]Calling fun:[{}], user_id:[{}],
|
||||
caller:[{}], start_time:[{:?}], error_code:[{}], error_msg:[{}]",
|
||||
"[ERROR]Calling fun:[{}], user_id:[{}], caller:[{}], start_time:[{:?}], error_code:[{}], error_msg:[{}]",
|
||||
func_name,
|
||||
calling_info.user_id(),
|
||||
owner_info,
|
||||
|
@ -47,6 +47,8 @@ static int32_t HuksErrorTransfer(int32_t ret)
|
||||
case HKS_ERROR_KEY_AUTH_FAILED:
|
||||
case HKS_ERROR_KEY_AUTH_VERIFY_FAILED:
|
||||
return ASSET_ACCESS_DENIED;
|
||||
case HKS_ERROR_CRYPTO_ENGINE_ERROR:
|
||||
return ASSET_DATA_CORRUPTED;
|
||||
default:
|
||||
return ASSET_CRYPTO_ERROR;
|
||||
}
|
||||
|
@ -79,7 +79,12 @@ impl SecretKey {
|
||||
auth_type: AuthType,
|
||||
access_type: Accessibility,
|
||||
require_password_set: bool,
|
||||
alias: Option<Vec<u8>>,
|
||||
) -> Result<Self> {
|
||||
if let Some(alias) = alias {
|
||||
return Ok(Self { auth_type, access_type, require_password_set, alias, calling_info: calling_info.clone() })
|
||||
}
|
||||
|
||||
// Check whether new key exists.
|
||||
let alias = calculate_key_alias(calling_info, auth_type, access_type, require_password_set, true)?;
|
||||
let new_key = Self { auth_type, access_type, require_password_set, alias, calling_info: calling_info.clone() };
|
||||
@ -139,19 +144,19 @@ impl SecretKey {
|
||||
let accessibilitys =
|
||||
[Accessibility::DevicePowerOn, Accessibility::DeviceFirstUnlocked, Accessibility::DeviceUnlocked];
|
||||
for accessibility in accessibilitys.into_iter() {
|
||||
let secret_key = SecretKey::new(calling_info, AuthType::None, accessibility, true)?;
|
||||
let secret_key = SecretKey::new(calling_info, AuthType::None, accessibility, true, None)?;
|
||||
let tmp = secret_key.delete();
|
||||
res = if tmp.is_err() { tmp } else { res };
|
||||
|
||||
let secret_key = SecretKey::new(calling_info, AuthType::Any, accessibility, true)?;
|
||||
let secret_key = SecretKey::new(calling_info, AuthType::Any, accessibility, true, None)?;
|
||||
let tmp = secret_key.delete();
|
||||
res = if tmp.is_err() { tmp } else { res };
|
||||
|
||||
let secret_key = SecretKey::new(calling_info, AuthType::None, accessibility, false)?;
|
||||
let secret_key = SecretKey::new(calling_info, AuthType::None, accessibility, false, None)?;
|
||||
let tmp = secret_key.delete();
|
||||
res = if tmp.is_err() { tmp } else { res };
|
||||
|
||||
let secret_key = SecretKey::new(calling_info, AuthType::Any, accessibility, false)?;
|
||||
let secret_key = SecretKey::new(calling_info, AuthType::Any, accessibility, false, None)?;
|
||||
let tmp = secret_key.delete();
|
||||
res = if tmp.is_err() { tmp } else { res };
|
||||
}
|
||||
|
31
services/db_key_operator/BUILD.gn
Normal file
31
services/db_key_operator/BUILD.gn
Normal file
@ -0,0 +1,31 @@
|
||||
# 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("//build/ohos.gni")
|
||||
|
||||
ohos_rust_static_library("asset_db_key_operator") {
|
||||
sources = [ "src/lib.rs" ]
|
||||
deps = [
|
||||
"../../../../../third_party/rust/crates/rust-openssl/openssl:lib",
|
||||
"../../frameworks/definition:asset_definition",
|
||||
"../../frameworks/os_dependency/file:asset_file_operator",
|
||||
"../../frameworks/os_dependency/log:asset_log",
|
||||
"../common:asset_common",
|
||||
"../crypto_manager:asset_crypto_manager",
|
||||
]
|
||||
|
||||
crate_name = "asset_db_key_operator"
|
||||
crate_type = "rlib"
|
||||
subsystem_name = "security"
|
||||
part_name = "asset"
|
||||
}
|
28
services/db_key_operator/Cargo.toml
Normal file
28
services/db_key_operator/Cargo.toml
Normal 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.
|
||||
|
||||
[package]
|
||||
name = "asset_db_key_operator"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
openssl = { git = "https://gitee.com/openharmony/third_party_rust_rust-openssl.git" }
|
||||
|
||||
asset_common = { path = "../common" }
|
||||
asset_crypto_manager = { path = "../crypto_manager" }
|
||||
asset_definition = { path = "../../frameworks/definition" }
|
||||
asset_file_operator = { path = "../../frameworks/os_dependency/file" }
|
||||
asset_log = { path = "../../frameworks/os_dependency/log" }
|
125
services/db_key_operator/src/lib.rs
Normal file
125
services/db_key_operator/src/lib.rs
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//! This module implements functions related to Asset database key.
|
||||
|
||||
use asset_common::CallingInfo;
|
||||
use asset_crypto_manager::{crypto::Crypto, secret_key::SecretKey};
|
||||
use asset_definition::{Accessibility, AuthType, Result};
|
||||
use asset_file_operator::ce_operator::{is_db_key_cipher_file_exist, read_db_key_cipher, write_db_key_cipher};
|
||||
use asset_log::logi;
|
||||
use openssl::rand::rand_bytes;
|
||||
use std::sync::Mutex;
|
||||
|
||||
fn build_db_key_secret_key(calling_info: &CallingInfo) -> Result<SecretKey> {
|
||||
let auth_type = AuthType::None;
|
||||
let access_type = Accessibility::DeviceFirstUnlocked;
|
||||
let require_password_set = false;
|
||||
let alias = "db_key_secret_key".as_bytes().to_vec();
|
||||
|
||||
SecretKey::new(calling_info, auth_type, access_type, require_password_set, Some(alias))
|
||||
}
|
||||
|
||||
static GEN_KEY_MUTEX: Mutex<()> = Mutex::new(());
|
||||
static GET_DB_KEY_MUTEX: Mutex<()> = Mutex::new(());
|
||||
|
||||
/// Generate secret key if it does not exist.
|
||||
pub fn generate_secret_key_if_needed(secret_key: &SecretKey) -> Result<()> {
|
||||
match secret_key.exists() {
|
||||
Ok(true) => Ok(()),
|
||||
Ok(false) => {
|
||||
let _lock = GEN_KEY_MUTEX.lock().unwrap();
|
||||
match secret_key.exists() {
|
||||
Ok(true) => Ok(()),
|
||||
Ok(false) => {
|
||||
logi!("[INFO]The key does not exist, generate it.");
|
||||
secret_key.generate()
|
||||
},
|
||||
Err(ret) => Err(ret),
|
||||
}
|
||||
},
|
||||
Err(ret) => Err(ret),
|
||||
}
|
||||
}
|
||||
|
||||
/// db key obj
|
||||
pub struct DbKey {
|
||||
/// db key
|
||||
pub db_key: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DbKey {
|
||||
/// Decrypt db key cipher.
|
||||
pub fn decrypt_db_key_cipher(calling_info: &CallingInfo, db_key_cipher: &Vec<u8>) -> Result<DbKey> {
|
||||
let secret_key = build_db_key_secret_key(calling_info)?;
|
||||
let aad: Vec<u8> = "trivial_aad_for_db_key".as_bytes().to_vec();
|
||||
let db_key = Crypto::decrypt(&secret_key, db_key_cipher, &aad)?;
|
||||
Ok(Self { db_key })
|
||||
}
|
||||
|
||||
fn generate_db_key() -> Result<DbKey> {
|
||||
const KEY_LEN_IN_BYTES: usize = 32; // aes-256-gcm requires key length 256 bits = 32 bytes.
|
||||
let mut db_key = [0; KEY_LEN_IN_BYTES];
|
||||
rand_bytes(&mut db_key).unwrap();
|
||||
Ok(Self { db_key: db_key.to_vec() })
|
||||
}
|
||||
|
||||
fn encrypt_db_key(&self, calling_info: &CallingInfo) -> Result<Vec<u8>> {
|
||||
let secret_key = build_db_key_secret_key(calling_info)?;
|
||||
generate_secret_key_if_needed(&secret_key)?;
|
||||
let aad: Vec<u8> = "trivial_aad_for_db_key".as_bytes().to_vec();
|
||||
let db_key_cipher = Crypto::encrypt(&secret_key, &self.db_key, &aad)?;
|
||||
|
||||
Ok(db_key_cipher)
|
||||
}
|
||||
|
||||
/// Check whether the database key exists.
|
||||
pub fn check_existance(user_id: i32) -> Result<bool> {
|
||||
is_db_key_cipher_file_exist(user_id)
|
||||
}
|
||||
|
||||
/// Read db key cipher and decrypt if the db key cipher file exists, generate db_key if not.
|
||||
pub fn get_db_key(calling_info: &CallingInfo) -> Result<DbKey> {
|
||||
match is_db_key_cipher_file_exist(calling_info.user_id()) {
|
||||
Ok(true) => {
|
||||
let db_key_cipher = read_db_key_cipher(calling_info.user_id())?;
|
||||
Self::decrypt_db_key_cipher(calling_info, &db_key_cipher)
|
||||
},
|
||||
Ok(false) => {
|
||||
let _lock = GET_DB_KEY_MUTEX.lock().unwrap();
|
||||
match is_db_key_cipher_file_exist(calling_info.user_id()) {
|
||||
Ok(true) => {
|
||||
let db_key_cipher = read_db_key_cipher(calling_info.user_id())?;
|
||||
Self::decrypt_db_key_cipher(calling_info, &db_key_cipher)
|
||||
},
|
||||
Ok(false) => {
|
||||
let db_key = Self::generate_db_key()?;
|
||||
let db_key_cipher = db_key.encrypt_db_key(calling_info)?;
|
||||
write_db_key_cipher(calling_info.user_id(), &db_key_cipher)?;
|
||||
Ok(db_key)
|
||||
},
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DbKey {
|
||||
fn drop(&mut self) {
|
||||
self.db_key.fill(0);
|
||||
}
|
||||
}
|
@ -21,8 +21,10 @@ ohos_rust_static_library("asset_db_operator") {
|
||||
deps = [
|
||||
":asset_sqlite3_wrapper",
|
||||
"../../frameworks/definition:asset_definition",
|
||||
"../../frameworks/os_dependency/file:asset_file_operator",
|
||||
"../../frameworks/os_dependency/log:asset_log",
|
||||
"../common:asset_common",
|
||||
"../db_key_operator:asset_db_key_operator",
|
||||
]
|
||||
|
||||
crate_name = "asset_db_operator"
|
||||
@ -37,8 +39,10 @@ ohos_rust_unittest("asset_db_operator_test") {
|
||||
deps = [
|
||||
":asset_sqlite3_wrapper",
|
||||
"../../frameworks/definition:asset_definition",
|
||||
"../../frameworks/os_dependency/file:asset_file_operator",
|
||||
"../../frameworks/os_dependency/log:asset_log",
|
||||
"../common:asset_common",
|
||||
"../db_key_operator:asset_db_key_operator",
|
||||
]
|
||||
subsystem_name = "security"
|
||||
part_name = "asset"
|
||||
|
@ -21,4 +21,6 @@ edition = "2021"
|
||||
[dependencies]
|
||||
asset_common = { path = "../common" }
|
||||
asset_definition = { path = "../../frameworks/definition" }
|
||||
asset_log = { path = "../../frameworks/os_dependency/log" }
|
||||
asset_log = { path = "../../frameworks/os_dependency/log" }
|
||||
asset_db_key_operator = { path = "../db_key_operator" }
|
||||
asset_file_operator = { path = "../../frameworks/os_dependency/file" }
|
||||
|
@ -19,9 +19,11 @@
|
||||
use core::ffi::c_void;
|
||||
use std::{ffi::CStr, fs, ptr::null_mut, sync::Mutex};
|
||||
|
||||
use asset_common::OwnerType;
|
||||
use asset_definition::{log_throw_error, ErrCode, Extension, Result, Value};
|
||||
use asset_common::{CallingInfo, OwnerType};
|
||||
use asset_definition::{log_throw_error, AssetMap, ErrCode, Extension, Result, Tag, Value};
|
||||
use asset_file_operator::{ce_operator::remove_ce_files, common::is_file_exist};
|
||||
use asset_log::{loge, logi};
|
||||
use asset_db_key_operator::DbKey;
|
||||
|
||||
use crate::{
|
||||
statement::Statement,
|
||||
@ -30,6 +32,7 @@ use crate::{
|
||||
column, sqlite_err_handle, DbMap, QueryOptions, COLUMN_INFO, DB_UPGRADE_VERSION, DB_UPGRADE_VERSION_V1,
|
||||
DB_UPGRADE_VERSION_V2, SQLITE_OK, TABLE_NAME, UPGRADE_COLUMN_INFO, UPGRADE_COLUMN_INFO_V2,
|
||||
},
|
||||
database_file_upgrade::{check_and_split_db, construct_splited_db_name, fmt_old_de_db_path},
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
@ -38,26 +41,48 @@ extern "C" {
|
||||
fn SqliteExec(db: *mut c_void, sql: *const u8, msg: *mut *mut u8) -> i32;
|
||||
fn SqliteFree(data: *mut c_void);
|
||||
fn SqliteErrMsg(db: *mut c_void) -> *const u8;
|
||||
fn SqliteKey(db: *mut c_void, pKey: *const c_void, nKey: i32) -> i32;
|
||||
}
|
||||
|
||||
/// each user have a Database file
|
||||
pub(crate) struct UserDbLock {
|
||||
pub(crate) user_id: i32,
|
||||
pub(crate) mtx: Mutex<i32>,
|
||||
#[allow(dead_code)]
|
||||
pub(crate) db_file_name: String,
|
||||
}
|
||||
|
||||
static USER_DB_LOCK_LIST: Mutex<Vec<&'static UserDbLock>> = Mutex::new(Vec::new());
|
||||
static SPLIT_DB_LOCK_LIST: Mutex<Vec<&'static UserDbLock>> = Mutex::new(Vec::new());
|
||||
pub(crate) static OLD_DB_NAME: &str = "asset";
|
||||
|
||||
/// If the user exists, the reference to the lock is returned.
|
||||
/// Otherwise, a new lock is created and its reference is returned.
|
||||
fn get_file_lock_by_user_id(user_id: i32) -> &'static UserDbLock {
|
||||
let mut list = USER_DB_LOCK_LIST.lock().unwrap();
|
||||
pub(crate) fn get_split_db_lock_by_user_id(user_id: i32) -> &'static UserDbLock {
|
||||
let mut list = SPLIT_DB_LOCK_LIST.lock().unwrap();
|
||||
for f in list.iter() {
|
||||
if f.user_id == user_id {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
let nf = Box::new(UserDbLock { user_id, mtx: Mutex::new(user_id) });
|
||||
let nf = Box::new(
|
||||
UserDbLock { user_id, mtx: Mutex::new(user_id), db_file_name: OLD_DB_NAME.clone().to_string() }
|
||||
);
|
||||
// SAFETY: We just push item into USER_DB_LOCK_LIST, never remove item or modify item,
|
||||
// so return a reference of leak item is safe.
|
||||
let nf: &'static UserDbLock = Box::leak(nf);
|
||||
list.push(nf);
|
||||
list[list.len() - 1]
|
||||
}
|
||||
|
||||
/// If the user exists, the reference to the lock is returned.
|
||||
/// Otherwise, a new lock is created and its reference is returned.
|
||||
pub(crate) fn get_file_lock_by_user_id_db_file_name(user_id: i32, db_file_name: String) -> &'static UserDbLock {
|
||||
let mut list = USER_DB_LOCK_LIST.lock().unwrap();
|
||||
for f in list.iter() {
|
||||
if f.user_id == user_id && f.db_file_name == db_file_name {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
let nf = Box::new(UserDbLock { user_id, mtx: Mutex::new(user_id), db_file_name });
|
||||
// SAFETY: We just push item into USER_DB_LOCK_LIST, never remove item or modify item,
|
||||
// so return a reference of leak item is safe.
|
||||
let nf: &'static UserDbLock = Box::leak(nf);
|
||||
@ -72,23 +97,19 @@ pub struct Database {
|
||||
pub(crate) backup_path: String,
|
||||
pub(crate) handle: usize, // Pointer to the database connection.
|
||||
pub(crate) db_lock: &'static UserDbLock,
|
||||
pub(crate) db_name: String,
|
||||
}
|
||||
|
||||
/// Callback for database upgrade.
|
||||
pub type UpgradeDbCallback = fn(db: &Database, old_ver: u32, new_ver: u32) -> Result<()>;
|
||||
|
||||
#[cfg(not(test))]
|
||||
const ROOT_PATH: &str = "/data/service/el1/public/asset_service";
|
||||
pub(crate) const DE_ROOT_PATH: &str = "/data/service/el1/public/asset_service";
|
||||
#[cfg(test)]
|
||||
const ROOT_PATH: &str = "/data/asset_test";
|
||||
pub(crate) const DE_ROOT_PATH: &str = "/data/asset_test";
|
||||
|
||||
#[inline(always)]
|
||||
fn fmt_db_path(user_id: i32) -> String {
|
||||
format!("{}/{}/asset.db", ROOT_PATH, user_id)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn fmt_backup_path(path: &str) -> String {
|
||||
pub(crate) fn fmt_backup_path(path: &str) -> String {
|
||||
let mut bp = path.to_string();
|
||||
bp.push_str(".backup");
|
||||
bp
|
||||
@ -96,33 +117,106 @@ fn fmt_backup_path(path: &str) -> String {
|
||||
|
||||
/// Get asset storage path.
|
||||
pub fn get_path() -> String {
|
||||
ROOT_PATH.to_string()
|
||||
DE_ROOT_PATH.to_string()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn fmt_ce_db_path_with_name(user_id: i32, db_name: &str) -> String {
|
||||
format!("data/service/el2/{}/asset_service/{}.db", user_id, db_name)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn fmt_de_db_path_with_name(user_id: i32, db_name: &str) -> String {
|
||||
format!("{}/{}/{}.db", DE_ROOT_PATH, user_id, db_name)
|
||||
}
|
||||
|
||||
fn check_validity_of_db_key(path: &str, user_id: i32) -> Result<()> {
|
||||
if is_file_exist(path)? && !DbKey::check_existance(user_id)? {
|
||||
loge!("[FATAL]There is database bot no database key. Now all data should be cleared and restart over.");
|
||||
remove_ce_files(user_id)?;
|
||||
return log_throw_error!(ErrCode::DataCorrupted, "[FATAL]All data is cleared in {}.", user_id)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn get_db(user_id: i32, db_name: &str, is_ce: bool) -> Result<Database> {
|
||||
let path = if is_ce {
|
||||
fmt_ce_db_path_with_name(user_id, db_name)
|
||||
} else {
|
||||
fmt_de_db_path_with_name(user_id, db_name)
|
||||
};
|
||||
let db_key = if is_ce {
|
||||
check_validity_of_db_key(&path, user_id)?;
|
||||
let calling_info = CallingInfo::new_part_info(user_id);
|
||||
match DbKey::get_db_key(&calling_info) {
|
||||
Ok(res) => Some(res),
|
||||
Err(e) if e.code == ErrCode::NotFound || e.code == ErrCode::DataCorrupted => {
|
||||
loge!("[FATAL]The key is corrupted. Now all data should be cleared and restart over, err is {}.",
|
||||
e.code);
|
||||
remove_ce_files(user_id)?;
|
||||
return log_throw_error!(ErrCode::DataCorrupted, "[FATAL]All data is cleared in {}.", user_id)
|
||||
}
|
||||
Err(e) => return Err(e)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let backup_path = fmt_backup_path(path.as_str());
|
||||
let lock = get_file_lock_by_user_id_db_file_name(user_id, db_name.to_string().clone());
|
||||
let mut db = Database { path, backup_path, handle: 0, db_lock: lock, db_name: db_name.to_string() };
|
||||
let _lock = db.db_lock.mtx.lock().unwrap();
|
||||
db.open_and_restore(db_key.as_ref())?;
|
||||
db.restore_if_exec_fail(|e: &Table| e.create(COLUMN_INFO))?;
|
||||
db.upgrade(DB_UPGRADE_VERSION, |_, _, _| Ok(()))?;
|
||||
Ok(db)
|
||||
}
|
||||
|
||||
/// Create de db instance if the value of tag "RequireAttrEncrypted" is not specified or set to false.
|
||||
/// Create ce db instance if true.
|
||||
pub fn create_db_instance(attributes: &AssetMap, calling_info: &CallingInfo) -> Result<Database> {
|
||||
match attributes.get(&Tag::RequireAttrEncrypted) {
|
||||
Some(Value::Bool(true)) => {
|
||||
let db = Database::build(calling_info, true)?;
|
||||
Ok(db)
|
||||
},
|
||||
_ => {
|
||||
let db = Database::build(calling_info, false)?;
|
||||
Ok(db)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl Database {
|
||||
/// Create a database.
|
||||
pub fn build(user_id: i32) -> Result<Database> {
|
||||
let path = fmt_db_path(user_id);
|
||||
let backup_path = fmt_backup_path(path.as_str());
|
||||
let lock = get_file_lock_by_user_id(user_id);
|
||||
let mut db = Database { path, backup_path, handle: 0, db_lock: lock };
|
||||
let _lock = db.db_lock.mtx.lock().unwrap();
|
||||
db.open_and_restore()?;
|
||||
db.restore_if_exec_fail(|e: &Table| e.create(COLUMN_INFO))?;
|
||||
db.upgrade(DB_UPGRADE_VERSION, |_, _, _| Ok(()))?;
|
||||
Ok(db)
|
||||
pub fn build(calling_info: &CallingInfo, is_ce: bool) -> Result<Database> {
|
||||
if !is_ce {
|
||||
// DE database needs trigger the upgrade action.
|
||||
check_and_split_db(calling_info.user_id())?;
|
||||
}
|
||||
get_db(
|
||||
calling_info.user_id(),
|
||||
&construct_splited_db_name(calling_info.owner_type_enum(),
|
||||
calling_info.owner_info(), is_ce)?, is_ce
|
||||
)
|
||||
}
|
||||
|
||||
/// check is db ok
|
||||
pub fn check_db_accessible(path: String, user_id: i32) -> Result<()> {
|
||||
let lock = get_file_lock_by_user_id(user_id);
|
||||
let mut db = Database { path: path.clone(), backup_path: path, handle: 0, db_lock: lock };
|
||||
/// Create a database from a file name.
|
||||
pub fn build_with_file_name(user_id: i32, db_name: &str, is_ce: bool) -> Result<Database> {
|
||||
check_and_split_db(user_id)?;
|
||||
get_db(user_id, db_name, is_ce)
|
||||
}
|
||||
|
||||
/// Check whether de db is ok
|
||||
pub fn check_de_db_accessible(path: String, user_id: i32, db_name: String) -> Result<()> {
|
||||
let lock = get_file_lock_by_user_id_db_file_name(user_id, db_name.clone());
|
||||
let mut db = Database { path: path.clone(), backup_path: path, handle: 0, db_lock: lock, db_name };
|
||||
db.open()?;
|
||||
let table = Table::new(TABLE_NAME, &db);
|
||||
table.create(COLUMN_INFO)
|
||||
}
|
||||
|
||||
// Open database connection.
|
||||
/// Open database connection.
|
||||
pub(crate) fn open(&mut self) -> Result<()> {
|
||||
let mut path_c = self.path.clone();
|
||||
path_c.push('\0');
|
||||
@ -137,8 +231,11 @@ impl Database {
|
||||
}
|
||||
|
||||
/// Open the database connection and restore the database if the connection fails.
|
||||
fn open_and_restore(&mut self) -> Result<()> {
|
||||
pub(crate) fn open_and_restore(&mut self, db_key: Option<&DbKey>) -> Result<()> {
|
||||
let result = self.open();
|
||||
if let Some(db_key) = db_key {
|
||||
self.set_db_key(db_key)?;
|
||||
}
|
||||
let result = match result {
|
||||
Err(ret) if ret.code == ErrCode::DataCorrupted => self.restore(),
|
||||
ret => ret,
|
||||
@ -146,6 +243,11 @@ impl Database {
|
||||
result
|
||||
}
|
||||
|
||||
/// Get db name.
|
||||
pub(crate) fn get_db_name(&mut self) -> &str {
|
||||
&self.db_name
|
||||
}
|
||||
|
||||
/// Close database connection.
|
||||
fn close(&mut self) {
|
||||
if self.handle != 0 {
|
||||
@ -160,6 +262,16 @@ impl Database {
|
||||
self.close()
|
||||
}
|
||||
|
||||
/// Encrypt/Decrypt CE database.
|
||||
pub fn set_db_key(&mut self, db_key: &DbKey) -> Result<()> {
|
||||
let ret = unsafe { SqliteKey(self.handle as _, db_key.db_key.as_ptr() as *const c_void, db_key.db_key.len() as i32) };
|
||||
if ret == SQLITE_OK {
|
||||
Ok(())
|
||||
} else {
|
||||
log_throw_error!(sqlite_err_handle(ret), "[FATAL][DB]Set database key failed, err={}", ret)
|
||||
}
|
||||
}
|
||||
|
||||
// Recovery the corrupt database and reopen it.
|
||||
pub(crate) fn restore(&mut self) -> Result<()> {
|
||||
loge!("[WARNING]Database is corrupt, start to restore");
|
||||
@ -213,7 +325,7 @@ impl Database {
|
||||
/// Delete database file.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn delete(user_id: i32) -> Result<()> {
|
||||
let path = fmt_db_path(user_id);
|
||||
let path = fmt_old_de_db_path(user_id);
|
||||
let backup_path = fmt_backup_path(&path);
|
||||
if let Err(e) = fs::remove_file(path) {
|
||||
return log_throw_error!(ErrCode::FileOperationError, "[FATAL][DB]Delete database failed, err={}", e);
|
||||
@ -437,6 +549,16 @@ impl Database {
|
||||
self.restore_if_exec_fail(closure)
|
||||
}
|
||||
|
||||
/// query how many data fit the query condition
|
||||
pub fn query_data_count(
|
||||
&mut self,
|
||||
condition: &DbMap,
|
||||
) -> Result<u32> {
|
||||
let _lock = self.db_lock.mtx.lock().unwrap();
|
||||
let closure = |e: &Table| e.count_datas(condition, false);
|
||||
self.restore_if_exec_fail(closure)
|
||||
}
|
||||
|
||||
/// Delete old data and insert new data.
|
||||
pub fn replace_datas(&mut self, condition: &DbMap, is_filter_sync: bool, datas: &DbMap) -> Result<()> {
|
||||
let _lock = self.db_lock.mtx.lock().unwrap();
|
||||
|
171
services/db_operator/src/database_file_upgrade.rs
Normal file
171
services/db_operator/src/database_file_upgrade.rs
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
//! This module provides interfaces for database management.
|
||||
//! Databases are isolated based on users and protected by locks.
|
||||
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use asset_common::OwnerType;
|
||||
use asset_definition::{log_throw_error, ErrCode, Extension, Result, Value};
|
||||
use asset_log::logi;
|
||||
|
||||
use crate::{
|
||||
database::{fmt_backup_path, fmt_de_db_path_with_name, get_db, get_split_db_lock_by_user_id, Database, OLD_DB_NAME, DE_ROOT_PATH}, types::{
|
||||
column, DbMap, QueryOptions,
|
||||
}
|
||||
};
|
||||
|
||||
const MINIM_OWNER_INFO_LEN: usize = 3;
|
||||
const REMOVE_INDEX: usize = 2;
|
||||
static MAX_BATCH_NUM: u32 = 100;
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn fmt_old_de_db_path(user_id: i32) -> String {
|
||||
format!("{}/{}/asset.db", DE_ROOT_PATH, user_id)
|
||||
}
|
||||
|
||||
fn check_old_db_exist(user_id: i32) -> bool {
|
||||
let path_str = fmt_old_de_db_path(user_id);
|
||||
let path = Path::new(&path_str);
|
||||
path.exists()
|
||||
}
|
||||
|
||||
/// Use owner_type and owner_info construct db name.
|
||||
pub fn construct_splited_db_name(owner_type: OwnerType, owner_info: &[u8], is_ce: bool) -> Result<String> {
|
||||
let mut res: String = match owner_type {
|
||||
OwnerType::Hap => {
|
||||
let owner_info_string = String::from_utf8_lossy(owner_info).to_string();
|
||||
let split_owner_info: Vec<&str> = owner_info_string.split('_').collect();
|
||||
if split_owner_info.len() < MINIM_OWNER_INFO_LEN || split_owner_info.last().is_none() {
|
||||
return log_throw_error!(ErrCode::DatabaseError, "[FATAL]The queried owner info is not correct.");
|
||||
}
|
||||
let app_index = split_owner_info.last().unwrap();
|
||||
let mut split_owner_info_mut = split_owner_info.clone();
|
||||
for _ in 0..REMOVE_INDEX {
|
||||
split_owner_info_mut.pop();
|
||||
}
|
||||
let owner_info = split_owner_info_mut.join("_").clone();
|
||||
format!("Hap_{}_{}", owner_info, app_index)
|
||||
},
|
||||
OwnerType::Native => {
|
||||
format!("Native_{}", String::from_utf8_lossy(owner_info))
|
||||
}
|
||||
};
|
||||
if is_ce {
|
||||
res = format!("enc_{}", res)
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn get_db_before_split(user_id: i32) -> Result<Database> {
|
||||
get_db(user_id, OLD_DB_NAME, false)
|
||||
}
|
||||
|
||||
fn get_value_from_db_map(db_map: &DbMap, key: &str) -> Result<Value> {
|
||||
match db_map.get(key) {
|
||||
Some(value) => Ok(value.clone()),
|
||||
_ => log_throw_error!(ErrCode::DatabaseError, "[FATAL]Get value from {} failed.", key)
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_old_db(user_id: i32) -> Result<()> {
|
||||
let mut remove_db_files = vec![];
|
||||
let path = fmt_de_db_path_with_name(user_id, OLD_DB_NAME);
|
||||
remove_db_files.push(path.clone());
|
||||
remove_db_files.push(fmt_backup_path(path.as_str()));
|
||||
for file_path in &remove_db_files {
|
||||
fs::remove_file(file_path)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_new_db(user_id: i32, info_map: &DbMap) -> Result<Database> {
|
||||
// 1.1 construct db name
|
||||
let owner_type = OwnerType::try_from(info_map.get_num_attr(&column::OWNER_TYPE)?.to_owned())?;
|
||||
let owner_info = info_map.get_bytes_attr(&column::OWNER)?;
|
||||
let new_db_name = construct_splited_db_name(owner_type, owner_info, false)?;
|
||||
// 1.2 construct new db
|
||||
get_db(user_id, &new_db_name, false)
|
||||
}
|
||||
|
||||
fn construct_old_query_condition(info_map: &DbMap) -> Result<DbMap> {
|
||||
let mut old_data_query_condition = DbMap::new();
|
||||
let owner_info = info_map.get_bytes_attr(&column::OWNER)?;
|
||||
old_data_query_condition.insert(column::OWNER, Value::Bytes(owner_info.clone()));
|
||||
Ok(old_data_query_condition)
|
||||
}
|
||||
|
||||
fn calculate_batch_split_times(old_data_query_condition: &DbMap, old_db: &mut Database) -> Result<u32> {
|
||||
let query_times = (old_db.query_data_count(old_data_query_condition)? + MAX_BATCH_NUM - 1) / MAX_BATCH_NUM;
|
||||
Ok(query_times)
|
||||
}
|
||||
|
||||
fn migrate_data(old_db: &mut Database, new_db: &mut Database, split_time: u32, old_data_query_condition: &DbMap) -> Result<()> {
|
||||
// 3.1 query data in old db
|
||||
let query_options = QueryOptions {offset: None, limit: Some(MAX_BATCH_NUM), order_by: None, order: None};
|
||||
|
||||
let old_data_vec =
|
||||
old_db.query_datas(&vec![], old_data_query_condition, Some(&query_options), false)?;
|
||||
// 3.2 insert data in new db
|
||||
for data in &old_data_vec {
|
||||
let mut condition = DbMap::new();
|
||||
condition.insert(column::ALIAS, get_value_from_db_map(data, column::ALIAS)?);
|
||||
condition.insert(column::OWNER, get_value_from_db_map(data, column::OWNER)?);
|
||||
condition.insert(column::OWNER_TYPE, get_value_from_db_map(data, column::OWNER_TYPE)?);
|
||||
let mut data_clone = data.clone();
|
||||
data_clone.remove(column::ID);
|
||||
new_db.replace_datas(&condition, false, &data_clone)?;
|
||||
// 3.3 remove data in old db
|
||||
old_db.delete_datas(&condition, None, false)?;
|
||||
}
|
||||
logi!("[INFO]Upgrade [{}] [{}]times", new_db.get_db_name(), split_time);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn split_db(user_id: i32) -> Result<()> {
|
||||
// 1. open old db
|
||||
let mut old_db = get_db_before_split(user_id)?;
|
||||
|
||||
// 2. get split db info
|
||||
let empty_condition = DbMap::new();
|
||||
let owner_info_db_list =
|
||||
old_db.query_datas(&vec![column::OWNER_TYPE, column::OWNER], &empty_condition, None, false)?;
|
||||
for info_map in &owner_info_db_list {
|
||||
// 1. get new db
|
||||
let mut new_db = get_new_db(user_id, info_map)?;
|
||||
// 2. batch insert data from old db to new db.
|
||||
let old_data_query_condition = construct_old_query_condition(info_map)?;
|
||||
for split_time in 0..calculate_batch_split_times(&old_data_query_condition, &mut old_db)? {
|
||||
migrate_data(&mut old_db, &mut new_db, split_time, &old_data_query_condition)?;
|
||||
}
|
||||
logi!("[INFO]Upgrade [{}] success!", new_db.get_db_name());
|
||||
}
|
||||
logi!("[INFO]Upgrade all db success!");
|
||||
remove_old_db(user_id)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// check db need split or not. If needed, split it by owner.
|
||||
pub fn check_and_split_db(user_id: i32) -> Result<()> {
|
||||
if check_old_db_exist(user_id) {
|
||||
let _lock = get_split_db_lock_by_user_id(user_id).mtx.lock().unwrap();
|
||||
if check_old_db_exist(user_id) {
|
||||
logi!("[INFO]Start split db.");
|
||||
split_db(user_id)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
@ -19,6 +19,7 @@ pub mod database;
|
||||
mod statement;
|
||||
mod table;
|
||||
mod transaction;
|
||||
pub mod database_file_upgrade;
|
||||
pub mod types;
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -112,3 +112,8 @@ int SqliteReset(void *pStmt)
|
||||
{
|
||||
return sqlite3_reset((sqlite3_stmt *)pStmt);
|
||||
}
|
||||
|
||||
int SqliteKey(void *db, const void *pKey, int nKey)
|
||||
{
|
||||
return sqlite3_key((sqlite3 *)db, pKey, nKey);
|
||||
}
|
@ -20,6 +20,7 @@ use std::{
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use asset_common::CallingInfo;
|
||||
use asset_definition::{ErrCode, Extension, Value};
|
||||
|
||||
use crate::{
|
||||
@ -60,7 +61,8 @@ fn open_db_and_insert_data() -> Database {
|
||||
create_dir();
|
||||
let mut def = DbMap::from(DB_DATA);
|
||||
add_bytes_column(&mut def);
|
||||
let mut db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let mut db = Database::build(&calling_info, false).unwrap();
|
||||
let count = db.insert_datas(&def).unwrap();
|
||||
assert_eq!(count, 1);
|
||||
db
|
||||
@ -81,7 +83,8 @@ fn backup_db(db: &Database) {
|
||||
#[test]
|
||||
fn create_and_drop_database() {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let mut db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let mut db = Database::build(&calling_info, false).unwrap();
|
||||
backup_db(&db);
|
||||
db.close_db();
|
||||
assert!(Database::delete(0).is_ok());
|
||||
@ -90,7 +93,8 @@ fn create_and_drop_database() {
|
||||
#[test]
|
||||
fn database_version() {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let db = Database::build(&calling_info, false).unwrap();
|
||||
assert_eq!(1, db.get_version().unwrap());
|
||||
assert!(db.set_version(2).is_ok());
|
||||
assert_eq!(2, db.get_version().unwrap());
|
||||
@ -100,7 +104,8 @@ fn database_version() {
|
||||
#[test]
|
||||
fn error_sql() {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let db = Database::build(&calling_info, false).unwrap();
|
||||
let sql = "pragma zzz user_version = {} mmm";
|
||||
assert!(db.exec(sql).is_err());
|
||||
let _ = Database::delete(0);
|
||||
@ -109,7 +114,8 @@ fn error_sql() {
|
||||
#[test]
|
||||
fn create_delete_asset_table() {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let mut db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let mut db = Database::build(&calling_info, false).unwrap();
|
||||
let table = Table::new(TABLE_NAME, &db);
|
||||
assert!(table.exist().unwrap());
|
||||
assert!(table.delete().is_ok());
|
||||
@ -124,7 +130,8 @@ fn insert_data_with_different_alias() {
|
||||
let mut def = DbMap::from(DB_DATA);
|
||||
add_bytes_column(&mut def);
|
||||
|
||||
let mut db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let mut db = Database::build(&calling_info, false).unwrap();
|
||||
let count = db.insert_datas(&def).unwrap();
|
||||
assert_eq!(count, 1);
|
||||
|
||||
@ -195,7 +202,8 @@ fn query_ordered_data() {
|
||||
let mut def = DbMap::from(DB_DATA);
|
||||
add_bytes_column(&mut def);
|
||||
|
||||
let mut db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let mut db = Database::build(&calling_info, false).unwrap();
|
||||
let count = db.insert_datas(&def).unwrap();
|
||||
assert_eq!(count, 1);
|
||||
|
||||
@ -229,7 +237,8 @@ fn insert_error_data() {
|
||||
create_dir();
|
||||
let mut datas = DbMap::new();
|
||||
datas.insert(column::OWNER, Value::Bytes(column::OWNER.as_bytes().to_vec()));
|
||||
let mut db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let mut db = Database::build(&calling_info, false).unwrap();
|
||||
assert!(db.insert_datas(&datas).is_err());
|
||||
remove_dir();
|
||||
}
|
||||
@ -245,7 +254,8 @@ fn backup_and_restore() {
|
||||
let _ = db_file.write(b"buffer buffer buffer").unwrap();
|
||||
|
||||
// Recovery the main database.
|
||||
let mut db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let mut db = Database::build(&calling_info, false).unwrap();
|
||||
let mut def = DbMap::from(DB_DATA);
|
||||
add_bytes_column(&mut def);
|
||||
|
||||
@ -272,7 +282,8 @@ fn query_mismatch_type_data() {
|
||||
let mut data = DbMap::from(DB_DATA);
|
||||
add_bytes_column(&mut data);
|
||||
data.insert(column::CREATE_TIME, Value::Number(1));
|
||||
let mut db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let mut db = Database::build(&calling_info, false).unwrap();
|
||||
db.insert_datas(&data).unwrap();
|
||||
|
||||
assert_eq!(ErrCode::FileOperationError, db.query_datas(&vec![], &data, None, false).unwrap_err().code);
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
use std::fs;
|
||||
|
||||
use asset_common::CallingInfo;
|
||||
use asset_definition::{DataType, Extension, Value};
|
||||
|
||||
use crate::{
|
||||
@ -31,7 +32,8 @@ fn create_delete_table() {
|
||||
ColumnInfo { name: "id", is_primary_key: true, not_null: true, data_type: DataType::Number },
|
||||
ColumnInfo { name: "alias", is_primary_key: false, not_null: true, data_type: DataType::Bytes },
|
||||
];
|
||||
let mut db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let mut db = Database::build(&calling_info, false).unwrap();
|
||||
let table = Table::new("table_name", &db);
|
||||
assert!(!table.exist().unwrap());
|
||||
assert!(table.create(columns).is_ok());
|
||||
@ -44,7 +46,8 @@ fn create_delete_table() {
|
||||
#[test]
|
||||
fn table_restore() {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let mut db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let mut db = Database::build(&calling_info, false).unwrap();
|
||||
let table = Table::new("table_name", &db);
|
||||
table
|
||||
.create(&[ColumnInfo { name: "Id", data_type: DataType::Number, is_primary_key: true, not_null: true }])
|
||||
@ -67,7 +70,8 @@ fn table_restore() {
|
||||
#[cfg(test)]
|
||||
fn insert_test_data() -> Database {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let db = Database::build(&calling_info, false).unwrap();
|
||||
let columns = &[
|
||||
ColumnInfo { name: "Id", is_primary_key: true, not_null: true, data_type: DataType::Number },
|
||||
ColumnInfo { name: "Owner", is_primary_key: false, not_null: true, data_type: DataType::Bytes },
|
||||
@ -135,7 +139,8 @@ fn data_life_circle() {
|
||||
#[test]
|
||||
fn single_data() {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let db = Database::build(&calling_info, false).unwrap();
|
||||
let table = Table::new("table_name", &db);
|
||||
let columns = &[
|
||||
ColumnInfo { name: "id", is_primary_key: true, not_null: true, data_type: DataType::Number },
|
||||
@ -166,7 +171,8 @@ fn single_data() {
|
||||
#[test]
|
||||
fn multiple_data() {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let db = Database::build(&calling_info, false).unwrap();
|
||||
let table = Table::new("table_name", &db);
|
||||
let columns = &[
|
||||
ColumnInfo { name: "id", is_primary_key: true, not_null: true, data_type: DataType::Number },
|
||||
@ -206,7 +212,8 @@ fn multiple_data() {
|
||||
#[test]
|
||||
fn insert_query_row() {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let db = Database::build(&calling_info, false).unwrap();
|
||||
let table = Table::new("table_name", &db);
|
||||
|
||||
let columns = &[
|
||||
@ -234,7 +241,8 @@ fn insert_query_row() {
|
||||
#[test]
|
||||
fn update_delete_row() {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let db = Database::build(&calling_info, false).unwrap();
|
||||
let table = Table::new("table_name", &db);
|
||||
|
||||
let columns = &[
|
||||
@ -260,7 +268,8 @@ fn update_delete_row() {
|
||||
#[test]
|
||||
fn upgrade_table() {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let db = Database::build(&calling_info, false).unwrap();
|
||||
let table = Table::new("table_name", &db);
|
||||
|
||||
let columns = &[
|
||||
@ -298,7 +307,8 @@ fn upgrade_table() {
|
||||
#[test]
|
||||
fn replace_datas() {
|
||||
fs::create_dir_all("/data/asset_test/0").unwrap();
|
||||
let db = Database::build(0).unwrap();
|
||||
let calling_info = CallingInfo::new_self();
|
||||
let db = Database::build(&calling_info, false).unwrap();
|
||||
let table = Table::new("table_name", &db);
|
||||
|
||||
let columns = &[
|
||||
|
@ -24,6 +24,8 @@ extern "C" {
|
||||
|
||||
bool GetUserIdByUid(uint64_t uid, uint32_t *userId);
|
||||
bool IsUserIdExist(int32_t userId, bool *exist);
|
||||
int32_t GetUserIds(int32_t *userIdsPtr, uint32_t *userIdsSize);
|
||||
int32_t GetUsersSize(uint32_t *userIdsSize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "os_account_manager.h"
|
||||
|
||||
#include "asset_type.h"
|
||||
#include "asset_log.h"
|
||||
|
||||
bool GetUserIdByUid(uint64_t uid, uint32_t *userId)
|
||||
@ -42,3 +43,50 @@ bool IsUserIdExist(int32_t userId, bool *exist)
|
||||
*exist = isUserIdExist;
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t GetUserIds(int32_t *userIdsPtr, uint32_t *userIdsSize)
|
||||
{
|
||||
std::vector<OHOS::AccountSA::OsAccountInfo> accountInfos = {};
|
||||
int32_t ret = OHOS::AccountSA::OsAccountManager::QueryAllCreatedOsAccounts(accountInfos);
|
||||
if (ret != OHOS::ERR_OK) {
|
||||
LOGE("[FATAL]Query all account id failed! res is %{public}d", ret);
|
||||
return ASSET_ACCOUNT_ERROR;
|
||||
}
|
||||
if (accountInfos.empty()) {
|
||||
LOGE("[FATAL]accountInfos is empty");
|
||||
return ASSET_ACCOUNT_ERROR;
|
||||
}
|
||||
std::vector<int32_t> userIdsVec = { 0 };
|
||||
std::transform(accountInfos.begin(), accountInfos.end(), std::back_inserter(userIdsVec),
|
||||
[](auto &iter) { return iter.GetLocalId(); });
|
||||
if (userIdsVec.size() > *userIdsSize) {
|
||||
LOGE("[FATAL]Users size increased after getting users size.");
|
||||
return ASSET_ACCOUNT_ERROR;
|
||||
}
|
||||
for (uint32_t i = 0; i < *userIdsSize; i++) {
|
||||
userIdsPtr[i] = userIdsVec[i];
|
||||
}
|
||||
*userIdsSize = static_cast<uint32_t>(userIdsVec.size());
|
||||
|
||||
return ASSET_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t GetUsersSize(uint32_t *userIdsSize)
|
||||
{
|
||||
std::vector<OHOS::AccountSA::OsAccountInfo> accountInfos = {};
|
||||
int32_t ret = OHOS::AccountSA::OsAccountManager::QueryAllCreatedOsAccounts(accountInfos);
|
||||
if (ret != OHOS::ERR_OK) {
|
||||
LOGE("[FATAL]Query all account id failed! res is %{public}d", ret);
|
||||
return ASSET_ACCOUNT_ERROR;
|
||||
}
|
||||
if (accountInfos.empty()) {
|
||||
LOGE("[FATAL]accountInfos is empty");
|
||||
return ASSET_ACCOUNT_ERROR;
|
||||
}
|
||||
std::vector<int32_t> userIdsVec = { 0 };
|
||||
std::transform(accountInfos.begin(), accountInfos.end(), std::back_inserter(userIdsVec),
|
||||
[](auto &iter) { return iter.GetLocalId(); });
|
||||
*userIdsSize = static_cast<uint32_t>(userIdsVec.size());
|
||||
|
||||
return ASSET_SUCCESS;
|
||||
}
|
@ -22,6 +22,7 @@ ohos_rust_static_library("asset_plugin") {
|
||||
"../../frameworks/utils:asset_utils",
|
||||
"../../interfaces/inner_api/rs:asset_sdk_rust",
|
||||
"../common:asset_common",
|
||||
"../db_key_operator:asset_db_key_operator",
|
||||
"../db_operator:asset_db_operator",
|
||||
"//third_party/rust/crates/libloading:lib",
|
||||
]
|
||||
|
@ -23,5 +23,6 @@ asset_common = { path = "../common" }
|
||||
asset_definition = { path = "../../frameworks/definition" }
|
||||
asset_log = { path = "../../frameworks/os_dependency/log" }
|
||||
asset_sdk = { path = "../../interfaces/inner_api/rs" }
|
||||
asset_db_key_operator = { path = "../db_key_operator" }
|
||||
asset_db_operator = { path = "../db_operator" }
|
||||
asset_file_operator = { path = "../../frameworks/os_dependency/file" }
|
||||
|
@ -13,18 +13,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use asset_common::Counter;
|
||||
use asset_db_operator::database::{get_path, Database};
|
||||
use asset_definition::{log_throw_error, ErrCode, Result};
|
||||
use asset_common::{CallingInfo, Counter, OwnerType};
|
||||
use asset_db_operator::{database::{get_path, Database}, database_file_upgrade::construct_splited_db_name, types::column};
|
||||
use asset_definition::{log_throw_error, ErrCode, Extension, Result};
|
||||
use asset_file_operator::de_operator::create_user_de_dir;
|
||||
use asset_log::{loge, logi};
|
||||
use asset_sdk::{
|
||||
plugin_interface::{ExtDbMap, IAssetPlugin, IAssetPluginCtx},
|
||||
Value,
|
||||
};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use std::{cell::RefCell, sync::{Arc, Mutex}};
|
||||
|
||||
/// The asset_ext plugin.
|
||||
#[derive(Default)]
|
||||
@ -100,103 +98,162 @@ impl AssetPlugin {
|
||||
/// The asset_ext plugin context.
|
||||
#[repr(C)]
|
||||
pub struct AssetContext {
|
||||
/// The asset database instance.
|
||||
pub data_base: Option<Database>,
|
||||
/// The asset databse's user id.
|
||||
pub user_id: i32,
|
||||
/// The asset databse's user id.
|
||||
pub calling_info: CallingInfo,
|
||||
}
|
||||
|
||||
fn get_db_name(attributes: &ExtDbMap, is_ce: bool) -> std::result::Result<String, u32> {
|
||||
let owner = attributes.get_bytes_attr(&column::OWNER).map_err(|e| e.code as u32)?;
|
||||
let owner_type = attributes.get_enum_attr::<OwnerType>(&column::OWNER_TYPE).map_err(|e| e.code as u32)?;
|
||||
// use owner and owner type calculate db file name
|
||||
construct_splited_db_name(owner_type, owner, is_ce).map_err(|e| e.code as u32)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl IAssetPluginCtx for AssetContext {
|
||||
/// Initializes the plugin before usage.
|
||||
fn init(&mut self, user_id: i32) -> std::result::Result<(), u32> {
|
||||
// Create database directory if not exists.
|
||||
asset_file_operator::create_user_db_dir(user_id).map_err(|e| e.code as u32)?;
|
||||
|
||||
let db = Database::build(user_id).map_err(|e| e.code as u32)?;
|
||||
self.data_base = Some(db);
|
||||
create_user_de_dir(user_id).map_err(|e| e.code as u32)?;
|
||||
self.user_id = user_id;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Adds an asset to the database.
|
||||
/// Adds an asset to de db.
|
||||
fn add(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
|
||||
self.data_base
|
||||
.as_mut()
|
||||
.ok_or(ErrCode::InvalidArgument as u32)?
|
||||
.insert_datas(attributes)
|
||||
.map_err(|e| e.code as u32)
|
||||
let db_name = get_db_name(attributes, false)?;
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
|
||||
db.insert_datas(attributes).map_err(|e| e.code as u32)
|
||||
}
|
||||
|
||||
/// Adds an asset to ce db.
|
||||
fn ce_add(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
|
||||
let db_name = get_db_name(attributes, true)?;
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
|
||||
db.insert_datas(attributes).map_err(|e| e.code as u32)
|
||||
}
|
||||
|
||||
/// Adds an asset with replace to de db.
|
||||
fn replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32> {
|
||||
self.data_base
|
||||
.as_mut()
|
||||
.ok_or(ErrCode::InvalidArgument as u32)?
|
||||
.replace_datas(condition, false, attributes)
|
||||
.map_err(|e| e.code as u32)
|
||||
let db_name = get_db_name(attributes, false)?;
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
|
||||
db.replace_datas(condition, false, attributes).map_err(|e| e.code as u32)
|
||||
}
|
||||
|
||||
/// Queries the asset database.
|
||||
/// Adds an asset with replace to ce db.
|
||||
fn ce_replace(&mut self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32> {
|
||||
let db_name = get_db_name(attributes, true)?;
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
|
||||
db.replace_datas(condition, false, attributes).map_err(|e| e.code as u32)
|
||||
}
|
||||
|
||||
/// Queries de db.
|
||||
fn query(&mut self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32> {
|
||||
self.data_base
|
||||
.as_mut()
|
||||
.ok_or(ErrCode::InvalidArgument as u32)?
|
||||
.query_datas(&vec![], attributes, None, false)
|
||||
.map_err(|e| e.code as u32)
|
||||
let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
|
||||
let mut query_data = vec![];
|
||||
for db_name in de_dbs {
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
|
||||
query_data.extend(db.query_datas(&vec![], attributes, None, false).map_err(|e| e.code as u32)?);
|
||||
}
|
||||
Ok(query_data)
|
||||
}
|
||||
|
||||
/// Removes an asset from the database.
|
||||
/// Queries ce db.
|
||||
fn ce_query(&mut self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32> {
|
||||
let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
|
||||
let mut query_data = vec![];
|
||||
for db_name in ce_dbs {
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
|
||||
query_data.extend(db.query_datas(&vec![], attributes, None, false).map_err(|e| e.code as u32)?);
|
||||
}
|
||||
Ok(query_data)
|
||||
}
|
||||
|
||||
/// Removes an asset from de db.
|
||||
fn remove(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
|
||||
self.data_base
|
||||
.as_mut()
|
||||
.ok_or(ErrCode::InvalidArgument as u32)?
|
||||
.delete_datas(attributes, None, false)
|
||||
.map_err(|e| e.code as u32)
|
||||
let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
|
||||
let mut total_remove_count = 0;
|
||||
for db_name in de_dbs {
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
|
||||
total_remove_count += db.delete_datas(attributes, None, false).map_err(|e| e.code as u32)?;
|
||||
}
|
||||
Ok(total_remove_count)
|
||||
}
|
||||
|
||||
/// Remove assets from the database with sepcific condition.
|
||||
/// Removes an asset from ce db.
|
||||
fn ce_remove(&mut self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
|
||||
let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
|
||||
let mut total_remove_count = 0;
|
||||
for db_name in ce_dbs {
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
|
||||
total_remove_count += db.delete_datas(attributes, None, false).map_err(|e| e.code as u32)?;
|
||||
}
|
||||
Ok(total_remove_count)
|
||||
}
|
||||
|
||||
/// Removes assets from de db with sepcific condition.
|
||||
fn remove_with_specific_cond(
|
||||
&mut self,
|
||||
specific_cond: &str,
|
||||
condition_value: &[Value],
|
||||
) -> std::result::Result<i32, u32> {
|
||||
self.data_base
|
||||
.as_mut()
|
||||
.ok_or(ErrCode::InvalidArgument as u32)?
|
||||
.delete_specific_condition_datas(specific_cond, condition_value)
|
||||
.map_err(|e| e.code as u32)
|
||||
let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
|
||||
let mut total_remove_count = 0;
|
||||
for db_name in de_dbs {
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
|
||||
total_remove_count += db.delete_specific_condition_datas(specific_cond, condition_value).map_err(|e| e.code as u32)?;
|
||||
}
|
||||
Ok(total_remove_count)
|
||||
}
|
||||
|
||||
/// Updates the attributes of an asset in the database.
|
||||
/// Removes assets from ce db with sepcific condition.
|
||||
fn ce_remove_with_specific_cond(
|
||||
&mut self,
|
||||
specific_cond: &str,
|
||||
condition_value: &[Value],
|
||||
) -> std::result::Result<i32, u32> {
|
||||
let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
|
||||
let mut total_remove_count = 0;
|
||||
for db_name in ce_dbs {
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
|
||||
total_remove_count += db.delete_specific_condition_datas(specific_cond, condition_value).map_err(|e| e.code as u32)?;
|
||||
}
|
||||
Ok(total_remove_count)
|
||||
}
|
||||
|
||||
/// Updates the attributes of an asset in de db.
|
||||
fn update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32> {
|
||||
self.data_base
|
||||
.as_mut()
|
||||
.ok_or(ErrCode::InvalidArgument as u32)?
|
||||
.update_datas(attributes, false, attrs_to_update)
|
||||
.map_err(|e| e.code as u32)
|
||||
let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
|
||||
let mut total_update_count = 0;
|
||||
for db_name in de_dbs {
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
|
||||
total_update_count += db.update_datas(attributes, false, attrs_to_update).map_err(|e| e.code as u32)?;
|
||||
}
|
||||
Ok(total_update_count)
|
||||
}
|
||||
|
||||
/// Begins a transaction for the asset database.
|
||||
fn begin_transaction(&mut self) -> std::result::Result<(), u32> {
|
||||
self.data_base
|
||||
.as_mut()
|
||||
.ok_or(ErrCode::InvalidArgument as u32)?
|
||||
.exec("begin immediate")
|
||||
.map_err(|e| e.code as u32)
|
||||
/// Updates the attributes of an asset in ce db.
|
||||
fn ce_update(&mut self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32> {
|
||||
let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
|
||||
let mut total_update_count = 0;
|
||||
for db_name in ce_dbs {
|
||||
let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
|
||||
total_update_count += db.update_datas(attributes, false, attrs_to_update).map_err(|e| e.code as u32)?;
|
||||
}
|
||||
Ok(total_update_count)
|
||||
}
|
||||
|
||||
/// Commits a transaction for the asset database.
|
||||
fn commit_transaction(&mut self) -> std::result::Result<(), u32> {
|
||||
self.data_base.as_mut().ok_or(ErrCode::InvalidArgument as u32)?.exec("commit").map_err(|e| e.code as u32)
|
||||
}
|
||||
|
||||
/// Rolls back a transaction for the asset database.
|
||||
fn rollback_transaction(&mut self) -> std::result::Result<(), u32> {
|
||||
self.data_base.as_mut().ok_or(ErrCode::InvalidArgument as u32)?.exec("rollback").map_err(|e| e.code as u32)
|
||||
}
|
||||
|
||||
/// Returns the storage path for the asset database.
|
||||
/// Returns the storage path for de db.
|
||||
fn get_storage_path(&self) -> String {
|
||||
get_path()
|
||||
}
|
||||
|
||||
/// Returns the storage path for ce db.
|
||||
fn ce_get_storage_path(&self) -> String {
|
||||
get_path()
|
||||
}
|
||||
|
||||
/// Increase count
|
||||
fn increase_count(&mut self) {
|
||||
let counter = Counter::get_instance();
|
||||
|
@ -65,7 +65,7 @@ fn grant_self_permission() -> i32 {
|
||||
fn generate_and_delete() {
|
||||
assert_eq!(0, grant_self_permission());
|
||||
let calling_info = CallingInfo::new(0, OwnerType::Native, vec![b'2']);
|
||||
let secret_key = SecretKey::new(&calling_info, AuthType::None, Accessibility::DevicePowerOn, false).unwrap();
|
||||
let secret_key = SecretKey::new(&calling_info, AuthType::None, Accessibility::DevicePowerOn, false, None).unwrap();
|
||||
secret_key.generate().unwrap();
|
||||
secret_key.exists().unwrap();
|
||||
let _ = SecretKey::delete_by_owner(&calling_info);
|
||||
@ -77,7 +77,7 @@ fn encrypt_and_decrypt() {
|
||||
assert_eq!(0, grant_self_permission());
|
||||
// generate key
|
||||
let calling_info = CallingInfo::new(0, OwnerType::Native, vec![b'2']);
|
||||
let secret_key = SecretKey::new(&calling_info, AuthType::None, Accessibility::DevicePowerOn, false).unwrap();
|
||||
let secret_key = SecretKey::new(&calling_info, AuthType::None, Accessibility::DevicePowerOn, false, None).unwrap();
|
||||
secret_key.generate().unwrap();
|
||||
|
||||
// encrypt data
|
||||
@ -98,7 +98,7 @@ fn encrypt_and_decrypt() {
|
||||
fn crypto_init() {
|
||||
assert_eq!(0, grant_self_permission());
|
||||
let calling_info = CallingInfo::new(0, OwnerType::Native, vec![b'2']);
|
||||
let secret_key = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false).unwrap();
|
||||
let secret_key = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false, None).unwrap();
|
||||
secret_key.generate().unwrap();
|
||||
|
||||
let mut crypto = Crypto::build(secret_key.clone(), 600).unwrap();
|
||||
@ -110,7 +110,7 @@ fn crypto_init() {
|
||||
fn crypto_exec() {
|
||||
assert_eq!(0, grant_self_permission());
|
||||
let calling_info = CallingInfo::new(0, OwnerType::Native, vec![b'2']);
|
||||
let secret_key = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false).unwrap();
|
||||
let secret_key = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false, None).unwrap();
|
||||
secret_key.generate().unwrap();
|
||||
|
||||
let msg = vec![1, 2, 3, 4, 5, 6];
|
||||
@ -128,12 +128,12 @@ fn crypto_exec() {
|
||||
fn crypto_manager() {
|
||||
assert_eq!(0, grant_self_permission());
|
||||
let calling_info = CallingInfo::new(0, OwnerType::Native, vec![b'2']);
|
||||
let secret_key1 = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false).unwrap();
|
||||
let secret_key1 = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false, None).unwrap();
|
||||
secret_key1.generate().unwrap();
|
||||
let mut crypto1 = Crypto::build(secret_key1.clone(), 600).unwrap();
|
||||
let challenge1 = crypto1.init_key().unwrap().clone();
|
||||
|
||||
let secret_key2 = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false).unwrap();
|
||||
let secret_key2 = SecretKey::new(&calling_info, AuthType::Any, Accessibility::DevicePowerOn, false, None).unwrap();
|
||||
secret_key2.generate().unwrap();
|
||||
let mut crypto2 = Crypto::build(secret_key2.clone(), 600).unwrap();
|
||||
let challenge2 = crypto2.init_key().unwrap().clone();
|
||||
|
Loading…
Reference in New Issue
Block a user