1. Description of folder decryption
Only the encrypted folder needs to be decrypted. When the same user views the same encrypted folder or the files / folders in it, he / she can view the same encrypted folder or the files / folders in it again after checking the password successfully every time. There is no need to enter the password. The password needs to be entered after 72 hours; (unless the password is changed, if the password is changed, it needs to be re entered. After the password is successfully verified for the first time, the calculation will start for 72 hours).
Note: check whether 72 hours is implemented on the client
2. Folder decryption process
1) Decryption process description
When accessing encrypted files:
First, go to the local database (sqlite) according to the scopeToken and path to find out whether the file has previously saved the decryption password
If it exists, it will check whether the data exceeds 72 hours. If not, take the password access interface Get:/api/plugin/wangpan/folders/:path of the data to check whether the password is correct:
If correct, enter the folder details and update the locally saved password and modification time of the folder;
Error: you need to re-enter the password and access the interface to verify whether the password is correct;
If the verification data is more than 72 hours, you need to enter the password and access the interface to verify whether the password is correct:
Update the locally saved password and modification time of the folder under correct conditions, and insert the password cache information of the file into the database;
Otherwise, the user will be prompted with the wrong password and re-enter it;
2) Main code implementation
/** * file */ public class HomeFragment extends BaseMVPDBFragment<FragmentHomeBinding, HomeContract.View, HomePresenter> implements HomeContract.View { ... /** * Initialization list */ private void initRv() { homeFileAdapter = new HomeFileAdapter(1, true); binding.rrv.setAdapter(homeFileAdapter) .setOnRefreshAndLoadMoreListener(refreshLoadMoreListener); homeFileAdapter.setOnItemClickListener((adapter, view, position) -> { mFileBean = homeFileAdapter.getItem(position); if (mFileBean.getType() == 0 && homeFileAdapter.getSelectedSize() <= 0) { // If it is a folder and is not in editing status if (mFileBean.getRead() == 1) { // Have read permission if (mFileBean.getIs_encrypt() == 1) { // Encrypted file mPresenter.getFolderPwdByScopeTokenAndPath(Constant.scope_token, mFileBean.getPath()); } else { // Unencrypted file filePwd = ""; toFolderDetail(false); } } else { // No read permission ToastUtil.show(UiUtil.getString(R.string.mine_without_read_permission)); } } }); ... } ... /** * Decrypt file successfully */ @Override public void decryptPwdSuccess() { if (inputPwdDialog != null && inputPwdDialog.isShowing()) { inputPwdDialog.dismiss(); } if (mFolderPwd == null) { mFolderPwd = new FolderPassword(Constant.USER_ID, mFileBean.getPath(), filePwd, Constant.scope_token, TimeUtil.getCurrentTimeMillis()); mPresenter.insertFolderPwd(mFolderPwd); } else { updateFolderPwd(); } toFolderDetail(true); } /** * Update folder password */ private void updateFolderPwd(){ mFolderPwd.setPassword(filePwd); mFolderPwd.setModifyTime(TimeUtil.getCurrentTimeMillis()); mPresenter.updateFolderPwd(mFolderPwd); } /** * Failed to decrypt file * * @param errorCode * @param msg */ @Override public void decryptPwdFail(int errorCode, String msg) { if (errorCode == ErrorConstant.PWD_ERROR) { // Folder password error if (inputPwdDialog != null && !inputPwdDialog.isShowing()) { filePwd = ""; updateFolderPwd(); inputPwdDialog.show(this); } } } /** * Password obtained successfully * * @param folderPassword */ @Override public void getFolderPwdByScopeTokenAndPathSuccess(FolderPassword folderPassword) { LogUtil.e("Query folder password succeeded"); if (folderPassword != null) { filePwd = folderPassword.getPassword(); long modifyTime = folderPassword.getModifyTime(); long distinct = TimeUtil.getCurrentTimeMillis() - modifyTime; mFolderPwd = folderPassword; if (TimeUtil.over72hour(distinct) || TextUtils.isEmpty(filePwd)) { // More than 72 hours showInputPwdDialog(); } else { checkFilePwd(); } } else { showInputPwdDialog(); } } /** * Failed to get password */ @Override public void getFolderPwdByScopeTokenAndPathFail() { LogUtil.e("Failed to query folder password"); showInputPwdDialog(); } } /** * presenter layer of file */ public class HomePresenter extends BasePresenter<HomeModel, HomeContract.View> implements HomeContract.Presenter { ... /** * Decrypt folder * @param scopeToken * @param path * @param checkPwdRequest */ @Override public void decryptFile(String scopeToken, String path, CheckPwdRequest checkPwdRequest) { executeObservable(mModel.decryptFile(scopeToken, path, checkPwdRequest), new RequestDataCallback<Object>(false) { @Override public void onSuccess(Object response) { super.onSuccess(response); if (mView!=null){ mView.decryptPwdSuccess(); } } @Override public void onFailed(int errorCode, String errorMessage) { super.onFailed(errorCode, errorMessage); if (mView!=null){ mView.decryptPwdFail(errorCode, errorMessage); } } }); } /** * Get locally saved folder password * @param scopeToken * @param path */ @Override public void getFolderPwdByScopeTokenAndPath(String scopeToken, String path) { executeDBObservable(mModel.getFolderPwdByScopeTokenAndPath(scopeToken, path), new RequestDataCallback<FolderPassword>() { @Override public void onSuccess(FolderPassword response) { super.onSuccess(response); if (mView!=null){ mView.getFolderPwdByScopeTokenAndPathSuccess(response); } } @Override public void onFailed() { super.onFailed(); if (mView!=null){ mView.getFolderPwdByScopeTokenAndPathFail(); } } }); } /** * Insert folder password * @param folderPassword */ @Override public void insertFolderPwd(FolderPassword folderPassword) { executeDBObservable(mModel.insertFolderPwd(folderPassword), new RequestDataCallback<Boolean>() { @Override public void onSuccess(Boolean response) { super.onSuccess(response); if (mView!=null){ if (response) { mView.insertFolderPwdSuccess(true); }else { mView.insertFolderFail(); } } } @Override public void onFailed() { super.onFailed(); if (mView!=null){ mView.insertFolderFail(); } } }); ... /** * Verify that the folder password is correct */ private void checkFilePwd() { if (mFileBean != null) { if (TextUtils.isEmpty(filePwd)){ // If the password is blank, enter inputPwdDialog.show(this); }else { // The password is not empty. Please verify the password CheckPwdRequest checkPwdRequest = new CheckPwdRequest(filePwd); mPresenter.decryptFile(Constant.scope_token, mFileBean.getPath(), checkPwdRequest); } } } } /** * Modify folder password * @param folderPassword */ @Override public void updateFolderPwd(FolderPassword folderPassword) { executeDBObservable(mModel.updateFolderPwd(folderPassword), new RequestDataCallback<Boolean>() { @Override public void onSuccess(Boolean response) { super.onSuccess(response); if (mView!=null) { if (response) { mView.updateFolderPwdSuccess(); } else { mView.updateFolderPwdFail(); } } } @Override public void onFailed() { super.onFailed(); if (mView!=null){ mView.updateFolderPwdFail(); } } }); } }
3) Database
Zhiting cloud disk stores folder password related information by using the Android local database SqLite. The database framework used is greendao (please refer to the official document for the use of greendao, which will not be repeated here). When searching for folder password, it is through the path and voucher of the folder. The following is the design of folder password related information table.
Table name | describe |
---|---|
id | Primary key id |
userId | User id |
path | Folder path |
password | Folder password |
scopeToken | voucher |
modifyTime | Creation / modification time |
The following is the model class of the folder password related information table:
@Entity public class FolderPassword { @Id(autoincrement = true) private Long id; // Primary key id private int userId; // User id private String path; // Folder path private String password; // Folder password private String scopeToken; // scopeToken private Long modifyTime; // Creation / modification time ... }