1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import Constants from '../common/constant'; 17import { EncryptSharingShowCodeEnum } from '../common/enum/EncryptSharingShowCodeEnum'; 18import EncryptSharingHelper from '../component/helper/EncryptSharingHelper'; 19import FileUtils, { FileMsg } from '../common/FileUtils/FileUtils'; 20import { getFileSizeByUriSync, isInvalidStr, isValidPath } from '../common/FileUtils/utils'; 21import { HiLog } from '../common/HiLog'; 22import Singleton from '../common/Singleton'; 23import { SupportTypesConfig } from '../common/SupportTypesConfig'; 24 25const TAG = 'UriValidator'; 26const DLP_FILE_TYPE = 'dlp'; 27 28interface IValidationHandler { 29 setNext(handler: IValidationHandler): IValidationHandler; 30 31 handle(context: ValidationContext): boolean; 32} 33 34interface UriValidationResult { 35 errorCode: number; 36 logMsg: string; 37 toastMsg: string | Resource; 38} 39 40abstract class BaseValidator implements IValidationHandler { 41 private nextHandler: IValidationHandler | null = null; 42 43 setNext(handler: IValidationHandler): IValidationHandler { 44 this.nextHandler = handler; 45 return handler; 46 } 47 48 handle(context: ValidationContext): boolean { 49 return this.nextHandler?.handle(context) ?? true; 50 } 51} 52 53class ValidationContext { 54 private _currentIndex: number = 0; 55 private _errorCode: number = EncryptSharingShowCodeEnum.SUCCESS; 56 public readonly uriList: string[]; 57 public fileTypes: string[]; 58 public fileSizes: number[]; 59 60 constructor( 61 uriList: string[], 62 fileTypes: string[] = [], 63 fileSizes: number[] = [] 64 ) { 65 this.uriList = uriList; 66 this.fileTypes = fileTypes; 67 this.fileSizes = fileSizes; 68 } 69 70 set currentIndex(index: number) { 71 this._currentIndex = index; 72 } 73 74 set errorCode(errorCode: number) { 75 this._errorCode = errorCode; 76 } 77 78 get currentUri(): string | null { 79 return this.uriList[this._currentIndex] ?? null; 80 } 81 82 get errorCode(): number { 83 return this._errorCode; 84 } 85 86 moveNext(): boolean { 87 if (this._currentIndex < this.uriList.length - 1) { 88 this._currentIndex++; 89 return true; 90 } 91 return false; 92 } 93} 94 95class FileCountValidator extends BaseValidator { 96 handle(context: ValidationContext): boolean { 97 HiLog.info(TAG, 'Enter FileCountValidator.'); 98 if (context.uriList.length <= 0 || context.uriList.length > Constants.SHARE_MAX_SUPPORT_NUMBER) { 99 context.errorCode = EncryptSharingShowCodeEnum.COUNT_ERROR; 100 return false; 101 } 102 return super.handle(context); 103 } 104} 105 106class FilePathValidator extends BaseValidator { 107 handle(context: ValidationContext): boolean { 108 HiLog.info(TAG, 'Enter FilePathValidator.'); 109 while (context.currentUri) { 110 if (isInvalidStr(context.currentUri) || !isValidPath(context.currentUri)) { 111 context.errorCode = EncryptSharingShowCodeEnum.FILE_PATH_ERROR; 112 return false; 113 } 114 if (!context.moveNext()) { 115 break; 116 } 117 } 118 return super.handle(context); 119 } 120} 121 122class FileTypeValidator extends BaseValidator { 123 handle(context: ValidationContext): boolean { 124 HiLog.info(TAG, 'Enter FileTypeValidator.'); 125 while (context.currentUri) { 126 const fileMsg: FileMsg = FileUtils.getSuffixFileMsgByUri(context.currentUri); 127 const dlpFileName: string = fileMsg.fileName + fileMsg.fileType + Constants.DLP_FILE_SUFFIX; 128 if (dlpFileName.length > Constants.DLP_FILE_LENGTH_LIMIT) { 129 context.errorCode = EncryptSharingShowCodeEnum.FILE_NAME_TOO_LONG; 130 return false; 131 } 132 133 const fileType: string = FileUtils.removeFileTypeFirstDot(fileMsg.fileType); 134 if (fileType && fileType.toLowerCase().indexOf(DLP_FILE_TYPE) !== -1) { 135 context.errorCode = EncryptSharingShowCodeEnum.FILE_ENCRYPTED_ERROR; 136 return false; 137 } 138 139 if (!SupportTypesConfig.checkType(fileType)) { 140 context.errorCode = EncryptSharingShowCodeEnum.SUPPORTED_TYPE_ERROR; 141 return false; 142 } 143 144 context.fileTypes.push(fileMsg.fileType); 145 if (!context.moveNext()) { 146 break; 147 } 148 } 149 return super.handle(context); 150 } 151} 152 153class FileSizeValidator extends BaseValidator { 154 handle(context: ValidationContext): boolean { 155 HiLog.info(TAG, 'Enter FileSizeValidator.'); 156 context.currentIndex = 0; 157 while (context.currentUri) { 158 const size = getFileSizeByUriSync(context.currentUri); 159 if (size === Constants.ERR_CODE_OPEN_FILE_ERROR) { 160 context.errorCode = EncryptSharingShowCodeEnum.FILE_PATH_ERROR; 161 return false; 162 } 163 164 const fileMsg: FileMsg = FileUtils.getSuffixFileMsgByUri(context.currentUri); 165 const fileType: string = FileUtils.removeFileTypeFirstDot(fileMsg.fileType); 166 if (SupportTypesConfig.isDocumentType(fileType)) { 167 if (size > Constants.SHARE_MAX_SUPPORT_SIZE_DOC) { 168 context.errorCode = EncryptSharingShowCodeEnum.SINGLE_SIZE_ERROR_DOC_MB; 169 return false; 170 } 171 } else { 172 if (size >= Constants.SHARE_MAX_SUPPORT_SIZE_IMAGE_VIDEO) { 173 context.errorCode = EncryptSharingShowCodeEnum.SINGLE_SIZE_ERROR_IMAGE_VIDEO_MB; 174 return false; 175 } 176 } 177 178 context.fileSizes.push(size); 179 180 if (!context.moveNext()) { 181 break; 182 } 183 } 184 return super.handle(context); 185 } 186} 187 188class DataPersistHandler extends BaseValidator { 189 handle(context: ValidationContext): boolean { 190 HiLog.info(TAG, 'Enter DataPersistHandler.'); 191 AppStorage.setOrCreate('hiFileTypeArray', context.fileTypes); 192 AppStorage.setOrCreate('hiFileSizeArray', context.fileSizes); 193 return super.handle(context); 194 } 195} 196 197export default class UriValidator { 198 public static singletonInstance: Singleton<UriValidator> = new Singleton<UriValidator>(() => new UriValidator()); 199 200 public static getInstance(): UriValidator { 201 return UriValidator.singletonInstance.getInstance(); 202 } 203 204 public validate(uriList: string[]): UriValidationResult { 205 HiLog.info(TAG, 'Enter URI validation.'); 206 const context = new ValidationContext(uriList); 207 const fileCountValidator = new FileCountValidator(); 208 const filePathValidator = new FilePathValidator(); 209 const fileTypeValidator = new FileTypeValidator(); 210 const fileSizeValidator = new FileSizeValidator(); 211 const dataPersistHandler = new DataPersistHandler(); 212 213 fileCountValidator.setNext(filePathValidator); 214 filePathValidator.setNext(fileTypeValidator); 215 fileTypeValidator.setNext(fileSizeValidator); 216 fileSizeValidator.setNext(dataPersistHandler); 217 218 fileCountValidator.handle(context); 219 return { 220 errorCode: context.errorCode, 221 logMsg: EncryptSharingHelper.getErrorMsg(context.errorCode) ?? '', 222 toastMsg: EncryptSharingHelper.getShowErr(context.errorCode) ?? '' 223 }; 224 } 225}