1. 文件夹解密说明
只有加密的文件夹才需要解密,同一用户在查看同一加密文件夹或者是里面的文件/文件夹,每次成功校验密码后,再次查看同一加密文件夹或里面的文件/文件夹,不用输入密码,72个小时后查看才需要输入密码;(除非有修改密码,如有修改密码,则需要重新输入,修改后第一次成功验证密码后再开始计算72小时)。
注:校验是否72小时是在客户端实现
2. 文件夹解密过程
1) 解密过程说明
我们在访问加密的文件时:
- 先去根据scopeToken和path去本地数据库(sqlite)查找该文件先前是否有保存解密密码
- 如果存在的话,则会校验该条数据是否超过72小时,在没有超过72小时的情况下就拿这条数据的密码访问接口Get:/api/plugin/wangpan/folders/:path 校验密码是否正确:
- 正确的话进入文件夹详情,并更新该文件夹本地保存的密码和修改时间;
- 错误需要重新输入密码并访问接口校验该密码是否正确;
- 校验数据是超过72小时的情况下,需要输入密码并访问接口校验该密码是否正确:
- 在正确的情况下更新该文件夹本地保存的密码和修改时间,并插入该文件的密码缓存信息到数据库;
- 否则提示用户密码错误,重新输入;
- 如果存在的话,则会校验该条数据是否超过72小时,在没有超过72小时的情况下就拿这条数据的密码访问接口Get:/api/plugin/wangpan/folders/:path 校验密码是否正确:
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; // 创建/修改时间
...
}