乐趣区

关于android:智汀云盘开发指南android端文件夹解密逻辑

1. 文件夹解密阐明

只有加密的文件夹才须要解密,同一用户在查看同一加密文件夹或者是外面的文件 / 文件夹,每次胜利校验明码后,再次查看同一加密文件夹或外面的文件 / 文件夹,不必输出明码,72 个小时后查看才须要输出明码;(除非有批改明码,如有批改明码,则须要从新输出,批改后第一次胜利验证明码后再开始计算 72 小时)。

注:校验是否 72 小时是在客户端实现

2. 文件夹解密过程

1)解密过程阐明

咱们在拜访加密的文件时:

先去依据 scopeToken 和 path 去本地数据库(sqlite)查找该文件先前是否有保留解密明码
如果存在的话,则会校验该条数据是否超过 72 小时,在没有超过 72 小时的状况下就拿这条数据的明码拜访接口 Get:/api/plugin/wangpan/folders/:path 校验明码是否正确:
正确的话进入文件夹详情,并更新该文件夹本地保留的明码和批改工夫;
谬误须要从新输出明码并拜访接口校验该明码是否正确;
校验数据是超过 72 小时的状况下,须要输出明码并拜访接口校验该明码是否正确:
在正确的状况下更新该文件夹本地保留的明码和批改工夫, 并插入该文件的明码缓存信息到数据库;
否则提醒用户明码谬误,从新输出;

2)次要代码实现

/**
 * 文件
 */
public class HomeFragment extends BaseMVPDBFragment<FragmentHomeBinding, HomeContract.View, HomePresenter> implements HomeContract.View {
    ...
         /**
     * 初始化列表
     */
    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 (mFileBean.getRead() == 1) {  // 有读权限
                    if (mFileBean.getIs_encrypt() == 1) { // 加密文件
                        mPresenter.getFolderPwdByScopeTokenAndPath(Constant.scope_token, mFileBean.getPath());
                    } else {  // 非加密文件
                        filePwd = "";
                        toFolderDetail(false);
                    }
                } else {  // 没有读权限
                    ToastUtil.show(UiUtil.getString(R.string.mine_without_read_permission));
                }
            }
        });

        ...
    }
    ...
        
     /**
     * 解密文件胜利
     */
    @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);
    }

    /**
     * 更新文件夹明码
     */
    private void updateFolderPwd(){mFolderPwd.setPassword(filePwd);
        mFolderPwd.setModifyTime(TimeUtil.getCurrentTimeMillis());
        mPresenter.updateFolderPwd(mFolderPwd);
    }

    /**
     * 解密文件失败
     *
     * @param errorCode
     * @param msg
     */
    @Override
    public void decryptPwdFail(int errorCode, String msg) {if (errorCode == ErrorConstant.PWD_ERROR) { // 文件夹明码谬误
            if (inputPwdDialog != null && !inputPwdDialog.isShowing()) {
                filePwd = "";
                updateFolderPwd();
                inputPwdDialog.show(this);
            }
        }
    }
     /**
     * 获取明码胜利
     *
     * @param folderPassword
     */
    @Override
    public void getFolderPwdByScopeTokenAndPathSuccess(FolderPassword folderPassword) {LogUtil.e("查问文件夹明码胜利");
        if (folderPassword != null) {filePwd = folderPassword.getPassword();
            long modifyTime = folderPassword.getModifyTime();
            long distinct = TimeUtil.getCurrentTimeMillis() - modifyTime;
            mFolderPwd = folderPassword;
            if (TimeUtil.over72hour(distinct) || TextUtils.isEmpty(filePwd)) {  // 超过 72 小时
                showInputPwdDialog();} else {checkFilePwd();
            }

        } else {showInputPwdDialog();
        }
    }

    /**
     * 获取明码失败
     */
    @Override
    public void getFolderPwdByScopeTokenAndPathFail() {LogUtil.e("查问文件夹明码失败");
        showInputPwdDialog();}
}



/**
 * 文件的 presenter 层
 */
public class HomePresenter extends BasePresenter<HomeModel, HomeContract.View> implements HomeContract.Presenter {
    ...
    /**
     * 解密文件夹
     * @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);
                }
            }
        });
    }

    /**
     * 获取本地保留的文件夹明码
     * @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();
                }
            }
        });
    }

    /**
     * 插入文件夹明码
     * @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();
                }
            }
        });
        
        ...
        /**
        * 校验文件夹明码是否正确
        */
        private void checkFilePwd() {if (mFileBean != null) {if (TextUtils.isEmpty(filePwd)){ // 如果明码为空,则输出
                    inputPwdDialog.show(this);
                }else { // 明码不为空,校验明码
                    CheckPwdRequest checkPwdRequest = new CheckPwdRequest(filePwd);
                    mPresenter.decryptFile(Constant.scope_token, mFileBean.getPath(), checkPwdRequest);
                }
            }
        }
    }

    /**
     * 批改文件夹明码
     * @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)数据库

智汀云盘存储文件夹明码相干信息的形式是应用 Android 本地数据库 SqLite,应用的数据库框架是 Greendao(greendao 的应用,请参照官网文档,这里不再赘述 greendao 的应用), 在查找文件夹明码时是通过文件夹的 path 和凭证查找的。上面是文件夹明码相干信息表的设计。

表名 形容
id 主键 id
userId 用户 id
path 文件夹门路
password 文件夹明码
scopeToken 凭证
modifyTime 创立 / 批改工夫

以下是文件夹明码相干信息表的 model 类:

@Entity
public class FolderPassword {@Id(autoincrement = true)
    private Long id;  // 主键 id
    private int userId;  // 用户 id
    private String path;  // 文件夹门路
    private String password; // 文件夹明码
    private String scopeToken;  // scopeToken
    private Long modifyTime;  // 创立 / 批改工夫
    ...
        
}

退出移动版