• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}