1/**
2 * Copyright (c) 2024-2024 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 { WidthPercent } from '../common/util/ConfigData';
17import HeadComponent from '../common/component/headComponent';
18import CmFaPresenter from '../presenter/CmFaPresenter';
19import { GlobalContext } from '../common/GlobalContext';
20import ComponentConfig from '../common/component/ComponentConfig';
21import router from '@ohos.router';
22import { CustomContentDialog } from '@ohos.arkui.advanced.Dialog';
23import checkUserAuthModel from '../model/CheckUserAuthModel';
24import { NavEntryKey } from '../common/NavEntryKey';
25import picker from '@ohos.file.picker';
26import FileIoModel from '../model/FileIoModel';
27import CmInstallPresenter from '../presenter/CmInstallPresenter';
28import { BusinessError } from '@ohos.base';
29import { RouterFileVo } from '../model/CertManagerVo/RouterInfoVo';
30import { CredPwdInputParam } from './picker/CredPwdInputPage';
31import { SheetParam } from './picker/SheetParam';
32
33const COPIES_NUM: number = 12;
34
35const TAG: string = 'CertInstallFromStorage: ';
36
37@Entry
38@Component
39export struct CertInstallFromStorage {
40  @State columnMargin: string = '12vp';
41  @State mFaPresenter: CmFaPresenter = CmFaPresenter.getInstance();
42  @State installCertFlag: boolean = false;
43  private context: Context = getContext(this);
44
45  isStartBySheetFirst: boolean = false;
46  isStartBySheet: boolean = false;
47  selected?: (path: string, param?: Object) => void;
48  @Prop sheetParam: SheetParam;
49  @State private headRectHeight: number = 64;
50  @State private headRectHeightReal: number = 0;
51  private scroller: Scroller = new Scroller();
52  @State private scrollerHeight: number = 0;
53
54  @Styles normalStyle() {
55    .backgroundColor($r('sys.color.ohos_id_color_card_bg'))
56    .borderRadius($r('app.float.user_list_divider_borderRadius_value'))
57  };
58  @Styles pressedStyle() {
59    .backgroundColor($r('sys.color.ohos_id_color_click_effect'))
60    .borderRadius($r('app.float.user_list_divider_borderRadius_value'))
61  };
62
63  rootCertificateDialog: CustomDialogController = new CustomDialogController({
64    alignment: DialogAlignment.Center,
65    builder: CustomContentDialog({
66      contentBuilder: () => {
67        this.rootCertificateContent();
68      },
69      contentAreaPadding: { right: $r('app.float.wh_value_0') },
70      buttons: [
71        {
72          value: $r('app.string.root_certificate_cancel'),
73          buttonStyle: ButtonStyleMode.TEXTUAL,
74          action: () => {
75          }
76        },
77        {
78          value: $r('app.string.root_certificate_continue'),
79          buttonStyle: ButtonStyleMode.TEXTUAL,
80          action: () => {
81            this.installCertFlag = true;
82            this.checkUserAuth();
83          }
84        }
85      ]
86    })
87  })
88
89  @Builder
90  rootCertificateContent(): void {
91    Column() {
92      Text($r('app.string.root_certificate'))
93        .height($r('app.float.wh_value_56'))
94        .fontSize($r('sys.float.ohos_id_text_size_dialog_tittle'))
95        .fontColor($r('sys.color.ohos_id_color_text_primary'))
96        .fontWeight(FontWeight.Medium)
97        .margin({
98          left: $r('app.float.wh_value_24'),
99          right: $r('app.float.wh_value_24')
100        })
101        .alignSelf(ItemAlign.Start)
102
103      Text($r('app.string.root_certificate_message'))
104        .fontSize($r('sys.float.ohos_id_text_size_body1'))
105        .fontWeight(FontWeight.Regular)
106        .fontColor($r('sys.color.ohos_id_color_primary'))
107        .margin({
108          left: $r('app.float.wh_value_24'),
109          right: $r('app.float.wh_value_24')
110        })
111        .alignSelf(ItemAlign.Start)
112    }
113    .width(WidthPercent.WH_100_100)
114    .borderRadius($r('app.float.user_list_divider_borderRadius_value'))
115    .backgroundColor($r('sys.color.ohos_id_color_dialog_bg'))
116  }
117
118  checkUserAuth() {
119    let titleStr = getContext().resourceManager.getStringSync($r('app.string.Identity_Authentication'));
120    checkUserAuthModel.auth(titleStr, (authResult: boolean) => {
121      if (authResult) {
122        console.info('checkUserAuth success');
123        if (this.installCertFlag) {
124          if (this.isStartBySheet) {
125            this.startInstallCertBySheet();
126          } else {
127            this.mFaPresenter.startInstallCert(this.context);
128          }
129        } else {
130          if (this.isStartBySheet) {
131            this.startInstallEvidenceBySheet();
132          } else {
133            this.mFaPresenter.startInstallEvidence(this.context);
134          }
135        }
136      }
137    })
138  }
139
140  startInstallCertBySheet(): void {
141    try {
142      let documentSelectOptions = new picker.DocumentSelectOptions();
143      let documentPicker = new picker.DocumentViewPicker(this.context);
144      console.info(TAG + 'start documentPicker.select');
145      documentPicker.select(documentSelectOptions).then((documentSelectResult) => {
146        if (documentSelectResult.length >= 1) {
147          this.routeToNextInstallCert(String(documentSelectResult[0]))
148        } else {
149          console.error(TAG + 'documentPicker.select length invalid:' + documentSelectResult.length);
150        }
151      }).catch((err: BusinessError) => {
152        console.error(TAG + 'documentPicker.select failed with err, message: ' + err.message + ', code: ' + err.code);
153      });
154    } catch (err) {
155      let e: BusinessError = err as BusinessError;
156      console.error(TAG + 'DocumentViewPicker failed with err, message: ' + e.message + ', code: ' + e.code);
157    }
158  }
159
160  routeToNextInstallCert(fileUri: string): void {
161    FileIoModel.getMediaFileSuffix(fileUri, (suffix: string | undefined) => {
162      if (suffix !== undefined) {
163        console.debug(TAG, 'suffix = ', suffix);
164        if ((suffix === 'cer') || (suffix === 'pem')) {
165          CmInstallPresenter.getInstance().installCert(fileUri, '', suffix, false);
166        } else {
167          this.mFaPresenter.unrecognizedFileTips();
168        }
169      }
170    })
171  }
172
173  startInstallEvidenceBySheet(): void {
174    try {
175      let documentSelectOptions = new picker.DocumentSelectOptions();
176      let documentPicker = new picker.DocumentViewPicker(this.context);
177      console.info(TAG + 'start documentPicker.select');
178      documentPicker.select(documentSelectOptions).then((documentSelectResult) => {
179        if (documentSelectResult.length >= 1) {
180          this.routeToNextInstallEvidence(String(documentSelectResult[0]))
181        } else {
182          console.error(TAG + 'documentPicker.select length invalid:' + documentSelectResult.length);
183        }
184      }).catch((err: BusinessError) => {
185        console.error(TAG + 'documentPicker.select failed with err, message: ' + err.message + ', code: ' + err.code);
186      });
187    } catch (err) {
188      let e: BusinessError = err as BusinessError;
189      console.error(TAG + 'DocumentViewPicker failed with err, message: ' + e.message + ', code: ' + e.code);
190    }
191  }
192
193  routeToNextInstallEvidence(fileUri: string): void {
194    FileIoModel.getMediaFileSuffix(fileUri, (suffix: string | undefined) => {
195      if (suffix !== undefined) {
196        console.debug(TAG, 'suffix = ', suffix);
197        if ((suffix === 'p12') || (suffix === 'pfx')) {
198          this.selected?.(NavEntryKey.CRED_PWD_INPUT_ENTRY, new CredPwdInputParam(new RouterFileVo(fileUri, suffix)));
199        } else {
200          this.mFaPresenter.unrecognizedFileTips();
201        }
202      }
203    })
204  }
205
206  build() {
207    Column() {
208      GridRow({
209        columns: COPIES_NUM,
210        gutter: vp2px(1) === 2 ? $r('app.float.wh_value_12') : $r('app.float.wh_value_0')
211      }) {
212        GridCol({ span: COPIES_NUM }) {
213          Row({}) {
214            Stack({ alignContent: Alignment.Top }) {
215              Column() {
216                HeadComponent({ headName: $r('app.string.installInStorageDevice'), isStartBySheet: this.isStartBySheet,
217                  icBackIsVisibility: !this.isStartBySheetFirst,
218                  onBackClicked: () => {
219                    this.selected?.(NavEntryKey.POP);
220                  }})
221                  .margin({
222                    top: this.isStartBySheet ? 8 : 0,
223                    left: 12,
224                    right: 12
225                  })
226              }.zIndex(1)
227              .onAreaChange((oldArea, newArea) => {
228                this.headRectHeight = newArea.height as number;
229                this.headRectHeightReal = newArea.height as number;
230              })
231
232              Stack({ alignContent: Alignment.TopEnd }) {
233                Scroll(this.scroller) {
234                  Column() {
235                    Row() {
236                      Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
237                        Text($r('app.string.CA_cert'))
238                          .fontSize($r('sys.float.ohos_id_text_size_body1'))
239                          .fontColor($r('sys.color.ohos_id_color_text_primary'))
240                          .fontWeight(FontWeight.Medium)
241                          .margin({ left: $r('app.float.wh_value_12') })
242                          .textAlign(TextAlign.Start)
243                      }
244                    }
245                    .stateStyles({
246                      normal: this.normalStyle,
247                      pressed: this.pressedStyle
248                    })
249                    .constraintSize({
250                      minHeight: $r('app.float.wh_value_48')
251                    })
252                    .onClick(() => {
253                      this.rootCertificateDialog.open();
254                    })
255
256                    Divider()
257                      .color($r('sys.color.ohos_id_color_list_separator'))
258                      .margin({
259                        left: $r('app.float.wh_value_12'),
260                        right: $r('app.float.wh_value_12')
261                      })
262
263                    Row() {
264                      Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
265                        Text($r('app.string.system_credentials'))
266                          .fontSize($r('sys.float.ohos_id_text_size_body1'))
267                          .fontColor($r('sys.color.ohos_id_color_text_primary'))
268                          .fontWeight(FontWeight.Medium)
269                          .margin({ left: $r('app.float.wh_value_12') })
270                          .textAlign(TextAlign.Start)
271                      }
272                      .onClick(() => {
273                        this.installCertFlag = false;
274                        AppStorage.setOrCreate('installSystemCred', true);
275                        AppStorage.setOrCreate('installUserCred',false);
276                        if (this.isStartBySheet) {
277                          this.startInstallEvidenceBySheet();
278                        } else {
279                          this.mFaPresenter.startInstallEvidence(this.context);
280                        }
281                      })
282                    }
283                    .stateStyles({
284                      normal: this.normalStyle,
285                      pressed: this.pressedStyle
286                    })
287                    .constraintSize({
288                      minHeight: $r('app.float.wh_value_48')
289                    })
290
291                    Divider()
292                      .color($r('sys.color.ohos_id_color_list_separator'))
293                      .margin({
294                        left: $r('app.float.wh_value_12'),
295                        right: $r('app.float.wh_value_12')
296                      })
297
298                    Row() {
299                      Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
300                        Text($r('app.string.user_certificate_credentials'))
301                          .fontSize($r('sys.float.ohos_id_text_size_body1'))
302                          .fontColor($r('sys.color.ohos_id_color_text_primary'))
303                          .fontWeight(FontWeight.Medium)
304                          .margin({ left: $r('app.float.wh_value_12') })
305                          .textAlign(TextAlign.Start)
306                      }
307                      .onClick(() => {
308                        this.installCertFlag = false;
309                        AppStorage.setOrCreate('installUserCred', true);
310                        AppStorage.setOrCreate('installSystemCred',false);
311                        if (this.isStartBySheet) {
312                          this.startInstallEvidenceBySheet();
313                        } else {
314                          this.mFaPresenter.startInstallEvidence(this.context);
315                        }
316                      })
317                    }
318                    .stateStyles({
319                      normal: this.normalStyle,
320                      pressed: this.pressedStyle
321                    })
322                    .constraintSize({
323                      minHeight: $r('app.float.wh_value_48')
324                    })
325                  }
326                  .padding($r('app.float.wh_value_4'))
327                  .backgroundColor($r('sys.color.ohos_id_color_card_bg'))
328                  .borderRadius($r('app.float.radius_20'))
329                  .width(ComponentConfig.WH_100_100)
330                }
331                .align(Alignment.Top)
332                .scrollable(ScrollDirection.Vertical)
333                .scrollBar(BarState.Off)
334                .width(WidthPercent.WH_100_100)
335                .edgeEffect(EdgeEffect.Spring)
336                .height(this.isStartBySheet ? WidthPercent.WH_AUTO : WidthPercent.WH_100_100)
337                .padding({
338                  left: 16,
339                  right: 16,
340                  bottom: $r('app.float.wh_value_24')
341                }).constraintSize({
342                  minHeight: this.getScrollMinHeight()
343                }).onAreaChange((oldArea, newArea) => {
344                  this.scrollerHeight = newArea.height as number;
345                })
346
347                Column() {
348                  ScrollBar({
349                    scroller: this.scroller,
350                    direction: ScrollBarDirection.Vertical,
351                    state: BarState.Auto
352                  }).margin({
353                    bottom: $r('app.float.wh_value_24')
354                  })
355                }.height(this.scrollerHeight)
356              }.padding({
357                top: this.headRectHeight
358              })
359            }
360            .backgroundColor($r('sys.color.ohos_id_color_sub_background'))
361            .width(WidthPercent.WH_100_100)
362            .height(this.isStartBySheet ? WidthPercent.WH_AUTO : WidthPercent.WH_100_100)
363          }
364          .width(WidthPercent.WH_100_100)
365          .height(this.isStartBySheet ? WidthPercent.WH_AUTO : WidthPercent.WH_100_100);
366        }
367      }
368      .width(WidthPercent.WH_100_100)
369      .height(this.isStartBySheet ? WidthPercent.WH_AUTO : WidthPercent.WH_100_100);
370    }
371    .backgroundColor($r('sys.color.ohos_id_color_sub_background'))
372    .width(WidthPercent.WH_100_100)
373    .height(this.isStartBySheet ? WidthPercent.WH_AUTO : WidthPercent.WH_100_100);
374  }
375
376  getScrollMinHeight() {
377    if (this.sheetParam === undefined || this.headRectHeightReal === 0 ||
378      this.sheetParam.sheetMinHeight < this.headRectHeightReal) {
379      return 0;
380    }
381    return this.sheetParam.sheetMinHeight - this.headRectHeightReal;
382  }
383
384  onPageShow() {
385    let uiExtensionFlag = GlobalContext.getContext().getFlag();
386    let installType: string = GlobalContext.getContext().getAbilityWant().parameters?.installType as string;
387    let uri = GlobalContext.getContext().getAbilityWant().uri ||
388      GlobalContext.getContext().getAbilityWant().parameters?.uri;
389    GlobalContext.getContext().clearAbilityWantUri();
390    GlobalContext.getContext().clearAbilityWantParamsUri();
391    if (uri === 'certInstall') {
392      router.pushUrl({
393        url: 'pages/certInstallFromStorage'
394      })
395    } else if (uri === 'requestAuthorize') {
396      this.mFaPresenter.startRequestAuth(GlobalContext.getContext().getAbilityWant().parameters?.appUid as string);
397    } else if (uiExtensionFlag && uri === 'systemCredInstall' && installType === 'systemCred') {
398      AppStorage.setOrCreate('installSystemCred', true);
399      AppStorage.setOrCreate('installUserCred', false);
400      this.mFaPresenter.startInstallEvidence(this.context);
401    } else if (uiExtensionFlag && uri === 'specifyInstall') {
402      let fileUri = GlobalContext.getContext().getAbilityWant().parameters?.fileUri as string;
403      this.mFaPresenter.startInstall(installType, fileUri);
404    } else {
405      console.error('The want type is not supported');
406    }
407  }
408}