Jelajahi Sumber

add: 查看证书详细信息弹窗UI;选择其他工具不能创建签名域

wzl 11 bulan lalu
induk
melakukan
e368d241cc

+ 1 - 1
packages/core/src/TextSelection.ts

@@ -160,7 +160,7 @@ export default class TextSelection {
   handleMouseDown(event: MouseEvent) {
     this.cleanSelection()
     const tool = this.tool
-    if (!markupType.includes(tool)) return
+    if (!markupType.includes(tool) || document.querySelector('.dialog')?.contains(event.target)) return
     const inPage = this.testPoint(event)
     if (!inPage) return
 

+ 1 - 1
packages/core/src/annotation/layer.js

@@ -687,7 +687,7 @@ class ComPDFAnnotationLayer {
         eventBus: this.eventBus,
         selectedElementName: this.selectedElementName
       })
-    } else if (['signatureFields', 'addDigitalSign', 'addElectronicSign'].includes(tool)) {
+    } else if (tool === 'signatureFields') {
       document.querySelector('.document').classList.add('annotation-edit')
       if (this.annotateManager) {
         this.annotateManager.reset()

+ 2 - 1
packages/core/src/form/signature_fields.js

@@ -574,7 +574,8 @@ export default class signatureFields extends Base {
 
   handleDelete (data) {
     const event = data instanceof Event ? data : null
-    if (!this.annotationContainer || data.name !== this.annotation.name) return
+    if (!this.annotationContainer) return
+    if (!event && data.name !== this.annotation.name) return
     if (this.layer.tool && event) {
       event.stopPropagation()
     }

+ 49 - 0
packages/webview/locales/en.json

@@ -215,6 +215,55 @@
       "startSigning": "Start Signing"
     },
 
+    "detailsDialog": {
+      "title": "Digital Signature Details",
+      "signBy": "Valid signature, signed by ",
+      "signingTime": "Signing Time",
+      "validitySummary": "Validity Summary",
+      "validIdentity": "The signer's identity is valid.",
+      "invalidIdentity": "The signer's identity is invalid.",
+      "unknownIdentity": "Signature validity is unknown because it has not been included in your list of trusted certificates and none of its parent certificates are trusted certificates.",
+      "expiredCertificate": "The file was signed with a certificate that has expired. If you acquired this file recently, it may not be authentic.",
+      "validSignature": "The signature is valid.",
+      "invalidSignature": "The signature is invalid.",
+      "notModifiedDoc": "The document has not been modified since this signature was applied.",
+      "alteredDoc": "The document has been altered or corrupted since it was signed by the current user.",
+      "viewCertificateDetails": "View Certificate Details"
+    },
+
+    "certificateViewerDialog": {
+      "title": "Certificate Viewer",
+      "abstracts": "Abstracts",
+      "summary": "Summary",
+      "issuedTo": "Issued to:",
+      "issuer": "Issuer",
+      "validFrom": "Valid from:",
+      "validTo": "Valid to:",
+      "intendedUsage": "Intended Usage:",
+
+      "details": "Details",
+      "version": "Version",
+      "algorithm": "Algorithm",
+      "subject": "Subject",
+      "serialNumber": "Serial Number",
+      "certificatePolicy": "Certificate Policy:",
+      "crlDistributionPoints": "CRL Distribution Points:",
+      "issuerInfoAccess": "Issuer Information Access:",
+      "issuerKeyIdentifier": "Issuer‘s Key Identifier:",
+      "subjectKeyIdentifier": "Subject‘s Key Identifier:",
+      "basicConstraints": "Basic Constraints:",
+      "keyUsage": "Key Usage:",
+      "publicKey": "Public Key:",
+      "X509": "X.509 Data:",
+      "SHA1Digest": "SHA1 Digest:",
+      "MD5Digest": "MD5 Digest:",
+
+      "trust": "Trust",
+      "trustedTo": "This Certificate Is Trusted to:",
+      "addToTrust": "Add to Trusted Certificates",
+      "done": "Done"
+    },
+
     "deleteConfirm": "Are you sure to delete it?"
   },
   "color": "Color",

+ 49 - 0
packages/webview/locales/zh-CN.json

@@ -215,6 +215,55 @@
       "startSigning": "开始签名"
     },
 
+    "detailsDialog": {
+      "title": "数字签名详细信息",
+      "signBy": "数字签名",
+      "signingTime": "签署时间",
+      "validitySummary": "有效性小结",
+      "validIdentity": "签名者的身份有效。",
+      "invalidIdentity": "签名者的身份无效。",
+      "unknownIdentity": "签名有效性未知,因为它未包含在您的受信任证书列表中,并且它的父证书都不是受信任证书。",
+      "expiredCertificate": "该文件是用已过期的证书签名的。如果您最近获取了此文件,则该文件可能不真实。",
+      "invalidSignature": "签名无效。",
+      "validSignature": "签名有效。",
+      "notModifiedDoc": "自应用此签名以来,文档未被修改。",
+      "alteredDoc": "自当前用户签署文档以来,该文档已被更改或损坏。",
+      "viewCertificateDetails": "查看证书细节"
+    },
+
+    "certificateViewerDialog": {
+      "title": "证书查看程序",
+      "abstracts": "摘要",
+      "summary": "小结",
+      "issuedTo": "颁发给",
+      "issuer": "颁发者",
+      "validFrom": "有效起始日期",
+      "validTo": "有效截止日期",
+      "intendedUsage": "预期用途",
+
+      "details": "详细信息",
+      "version": "版本",
+      "algorithm": "签名算法",
+      "subject": "主题",
+      "serialNumber": "序列号",
+      "certificatePolicy": "证书策略",
+      "crlDistributionPoints": "CRL分发点",
+      "issuerInfoAccess": "颁发机构信息访问",
+      "issuerKeyIdentifier": "颁发机构密钥标识符",
+      "subjectKeyIdentifier": "主体密钥标识符",
+      "basicConstraints": "基本约束",
+      "keyUsage": "密钥用法",
+      "publicKey": "公钥",
+      "X509": "X.509",
+      "SHA1Digest": "SHA1",
+      "MD5Digest": "MD5",
+
+      "trust": "信任",
+      "trustedTo": "本证书信任于:",
+      "addToTrust": "添加到可信任证书",
+      "done": "关闭"
+    },
+
     "deleteConfirm": "确定删除该内容?"
   },
   "color": "颜色",

+ 0 - 70
packages/webview/src/components/Dialogs/CertificationDetailsDialog.vue

@@ -1,70 +0,0 @@
-<template>
-  <div class="certification-details-dialog" v-if="show">
-    <Dialog :show="show" :dialogName="dialogName">
-      <template #header>
-        <p>Customize the Signature Appearance</p>
-        <CloseB class="close" @click="closePanel" />
-      </template>
-
-      <template #footer>
-        <div class="view-button">View</div>
-      </template>
-    </Dialog>
-  </div>
-</template>
-
-<script setup>
-import { computed } from 'vue'
-import { useViewerStore } from '@/stores/modules/viewer'
-
-const dialogName = 'certificationDetailsDialog'
-
-const useViewer = useViewerStore()
-
-const show = computed(() => useViewer.isElementOpen(dialogName))
-
-const closePanel = () => {
-  useViewer.closeElement(dialogName)
-}
-</script>
-
-<style lang="scss">
-.certification-details-dialog {
-
-  .dialog-container {
-    padding: 15px 23px;
-    width: 628px;
-    border-radius: 0;
-    position: relative;
-
-    header {
-      
-      p {
-        margin-left: -3px;
-        font-size: 14px;
-        line-height: 16px;
-        font-weight: 400;
-        color: var(--c-right-side-header-text);
-      }
-
-      .close {
-        position: absolute;
-        top: 8px;
-        right: 8px;
-        margin: 0;
-        cursor: pointer;
-      }
-    }
-
-    main {
-      margin-top: 24px;
-    }
-
-    footer {
-      .rect-button {
-        border-radius: 4px;
-      }
-    }
-  }
-}
-</style>

+ 275 - 0
packages/webview/src/components/Dialogs/CertificationViewerDialog.vue

@@ -0,0 +1,275 @@
+<template>
+  <div class="certification-details-dialog" v-if="show">
+    <Dialog :show="show" :dialogName="dialogName">
+      <template #header>
+        <p class="title">{{ $t('signatures.certificateViewerDialog.title') }}</p>
+        <p class="desc">{{ $t('signatures.certificateViewerDialog.title') }}</p>
+      </template>
+
+      <div class="container">
+        <div class="left">
+          <p :class="{ 'highlighted': isHighlighted === 0 }" @focus="isHighlighted = 0" @blur="isHighlighted = -1" tabindex="-1">ComPDFKit 1</p>
+          <p :class="{ 'highlighted': isHighlighted === 1 }" @focus="isHighlighted = 1" @blur="isHighlighted = -1" tabindex="-1">ComPDFKit 2</p>
+        </div>
+
+        <div class="right">
+          <div class="tabs">
+            <div @click="activePanel = 1" :class="{ active: activePanel === 1 }">{{ $t('signatures.certificateViewerDialog.abstracts') }}</div>
+            <div @click="activePanel = 2" :class="{ active: activePanel === 2 }">{{ $t('signatures.certificateViewerDialog.details') }}</div>
+            <div @click="activePanel = 3" :class="{ active: activePanel === 3 }">{{ $t('signatures.certificateViewerDialog.trust') }}</div>
+          </div>
+          <div class="panel">
+            <div class="summary">
+              <div class="title">
+                <div class="line-left"></div>
+                <span>{{ activePanel === 3 ? $t('signatures.certificateViewerDialog.trustedTo') : $t('signatures.certificateViewerDialog.summary') }}</span>
+                <div class="line-right"></div>
+              </div>
+              <div class="content">
+                <div v-show="activePanel === 1" class="abstracts">
+                  <p>{{ $t('signatures.certificateViewerDialog.issuedTo') }} <span>ComPDFKit&lt;12341234@qq.com&gt;</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.issuer') }} <span>ComPDFKit</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.validFrom') }} <span>2021/01/27 13:41:56 +08`00`</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.validTo') }} <span>Digital Signatures, Encrypted Documents, Key Agreements</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.intendedUsage') }} <span>Digital Signature, Non-Repudiation</span></p>
+                </div>
+
+                <div v-show="activePanel === 2" class="details">
+                  <p>{{ $t('signatures.certificateViewerDialog.version') }} <span>1.9.0</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.algorithm') }} <span>SHA - 256 with RSA encryption (1.2.840.113549.1.11)</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.subject') }} <span>C=CN,O=ComPDFKit</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.issuer') }} <span>ComPDFKit</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.serialNumber') }} <span>3223484506630560670</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.validFrom') }} <span>2021/01/27 13:41:56 +08`00`</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.validTo') }} <span>2021/01/27 13:41:56 +08`00`</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.certificatePolicy') }} <span>Windows Certificate Policy</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.crlDistributionPoints') }} <span>/</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.issuerInfoAccess') }} <span>223384759660</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.issuerKeyIdentifier') }} <span>223384759660</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.subjectKeyIdentifier') }} <span>/</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.basicConstraints') }} <span>View Detailed Information</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.keyUsage') }} <span>/</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.publicKey') }} <span>256 bytes: D3 10 27 F7 23</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.X509') }} <span>Unspecified value</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.SHA1Digest') }} <span>/</span></p>
+                  <p>{{ $t('signatures.certificateViewerDialog.MD5Digest') }} <span>50:28:38:22:09:34:63</span></p>
+                </div>
+
+                <div v-show="activePanel === 3" class="trust">
+                  <p><SuccessIcon /><span>Sign document or data</span></p>
+                  <p><FailedIcon /><span>Certify document</span></p>
+                </div>
+              </div>
+            </div>
+
+            <div v-show="activePanel === 3" class="trust-button">
+              <div @click="">{{ $t('signatures.certificateViewerDialog.addToTrust') }}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="rect-button blue" @click="close">{{ $t('signatures.certificateViewerDialog.done') }}</div>
+      </template>
+    </Dialog>
+  </div>
+</template>
+
+<script setup>
+import { computed, ref } from 'vue'
+import { useViewerStore } from '@/stores/modules/viewer'
+
+const dialogName = 'certificateViewerDialog'
+
+const useViewer = useViewerStore()
+
+const show = computed(() => useViewer.isElementOpen(dialogName))
+
+const activePanel = ref(1)
+const isHighlighted = ref(-1)
+
+const close = () => {
+  useViewer.closeElement(dialogName)
+}
+</script>
+
+<style lang="scss">
+.certification-details-dialog {
+
+  .dialog-container {
+    padding: 20px;
+    width: 1070px;
+    border-radius: 0;
+
+    header {
+      
+      .title {
+        font-size: 16px;
+        line-height: 24px;
+        font-weight: 700;
+        color: var(--c-right-side-header-text);
+      }
+
+      .desc {
+        margin-top: 20px;
+        font-size: 14px;
+        line-height: 16px;
+        font-weight: 400;
+      }
+    }
+
+    main {
+      margin: 32px 0;
+    }
+
+    footer {
+      .rect-button {
+        border-radius: 4px;
+      }
+    }
+  }
+
+  .container {
+    display: flex;
+
+    .left {
+      margin-right: 32px;
+      padding: 2px;
+      width: 246px;
+      border: 1px solid var(--c-header-border);
+
+      p {
+        padding: 4px;
+        font-size: 14px;
+        line-height: 16px;
+        color: var(--c-black-text);
+        cursor: default;
+
+        &.highlighted {
+          background: #1460F3;
+          color: white;
+        }
+      }
+    }
+
+    .right {
+      flex: 1;
+      border: 1px solid var(--c-header-border);
+      height: 700px;
+
+      .tabs {
+        display: flex;
+        justify-content: center;
+        border-bottom: 1px solid var(--c-header-border);
+
+        > div {
+          margin: 10px 12px -1px 12px;
+          padding-bottom: 4px;
+          font-size: 16px;
+          line-height: 24px;
+          cursor: pointer;
+
+          &.active {
+            color: var(--c-right-side-header-text);
+            font-weight: 700;
+            border-bottom: 2px solid #4982E6;
+          }
+        }
+      }
+
+      .panel {
+        padding: 20px;
+
+        .summary {
+          margin-top: 10px;
+          border: 1px solid var(--c-header-border);
+          border-top-width: 0px;
+
+          .title {
+            display: flex;
+
+            span {
+              margin: -12px 4px 0 4px;
+              font-size: 14px;
+              line-height: 20px;
+              font-weight: 600;
+              color: var(--c-black-text);
+            }
+
+            .line-left {
+              width: 12px;
+              border-top: 1px solid var(--c-header-border);
+            }
+
+            .line-right {
+              flex: 1;
+              border-top: 1px solid var(--c-header-border);
+            }
+          }
+
+          .content {
+            margin: 20px 20px 16px;
+            
+            p {
+              font-size: 14px;
+              line-height: 20px;
+
+              & + p {
+                margin-top: 12px;
+              }
+            }
+
+            span {
+              color: var(--c-side-annotation-text);
+            }
+
+            .details p {
+              color: var(--c-black-text);
+            }
+
+            .trust p {
+              display: flex;
+              align-items: center;
+              
+              span {
+                color: var(--c-right-side-header-text);
+              }
+
+              svg {
+                max-width: 20px;
+                width: 20px;
+                height: 20px;
+                margin-right: 4px;
+              }
+            }
+          }
+        }
+
+        .trust-button {
+          margin-top: 24px;
+          text-align: right;
+
+          > div {
+            padding: 0 12px;
+            display: inline-block;
+            height: 32px;
+            border: 1px solid var(--c-header-border);
+            border-radius: 1px;
+            background: var(--c-header-button-active);
+            cursor: pointer;
+            font-size: 14px;
+            line-height: 32px;
+            color: var(--c-right-side-header-text);
+
+            &:hover {
+              background: var(--c-popup-bg-hover);
+              color: white;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 6 - 1
packages/webview/src/components/Dialogs/Dialog.vue

@@ -1,7 +1,12 @@
 <template>
   <div v-if="show" class="dialog">
     <div class="dialog-container">
-      <div class="close" v-if="close"><Close @click="closeDialog" /></div>
+      <div class="close" v-if="close" @click="closeDialog">
+        <CloseA v-if="close === 'A'" />
+        <CloseB v-if="close === 'B'" />
+        <Close v-else />
+      </div>
+
       <header>
         <slot name="header"></slot>
       </header>

+ 16 - 11
packages/webview/src/components/Dialogs/SignatureDetailsDialog.vue

@@ -2,8 +2,8 @@
   <div class="signature-details-dialog" v-if="show">
     <Dialog :show="show" :dialogName="dialogName">
       <template #header>
-        <p>Digital Signature Details</p>
-        <CloseB class="close" @click="closePanel" />
+        <p>{{ $t('signatures.detailsDialog.title') }}</p>
+        <CloseB class="close" @click="close" />
       </template>
 
       <div class="info">
@@ -11,33 +11,33 @@
         <SignatureInvalid v-else-if="signature.state === 'invalid'" />
         <SignatureUnknown v-else />
         <div>
-          <p class="title">Valid signature,Signed by "ComPDFKit &lt;12341234@qq.com&gt;".</p>
-          <p class="desc">Signing Time:2023-8-11 05:00:53 PM/AM (EST)</p>
+          <p class="title">{{ $t('signatures.detailsDialog.signBy') }} "ComPDFKit &lt;12341234@qq.com&gt;".</p>
+          <p class="desc">{{ $t('signatures.detailsDialog.signingTime') }} 2023-8-11 05:00:53 PM/AM (EST)</p>
         </div>
       </div>
 
       <div class="summary">
         <div class="title">
           <div class="line-left"></div>
-          <span>Validity Summary</span>
+          <span>{{ $t('signatures.detailsDialog.validitySummary') }}</span>
           <div class="line-right"></div>
         </div>
         <div class="content">
-          The signer's identity is valid.
+          {{ $t('signatures.detailsDialog.validIdentity') }}
           <br>
           <br>
-          The signer's identity is invalid.
+          {{ $t('signatures.detailsDialog.invalidIdentity') }}
           <br>
           <br>
-          Signature validity is unknown because it has not been included in your list of trusted certificates and none of its parent certificates are trusted certificates.
+          {{ $t('signatures.detailsDialog.unknownIdentity') }}
           <br>
           <br>
-          The signature is valid.
+          {{ $t('signatures.detailsDialog.validSignature') }}
         </div>
       </div>
 
       <template #footer>
-        <div class="view-button">View Certificate Details</div>
+        <div class="view-button" @click="openDialog">{{ $t('signatures.detailsDialog.viewCertificateDetails') }}</div>
       </template>
     </Dialog>
   </div>
@@ -56,9 +56,14 @@ const useDocument = useDocumentStore()
 const show = computed(() => useViewer.isElementOpen(dialogName))
 const signature = computed(() => useDocument.getSelectedSignature)
 
-const closePanel = () => {
+const close = () => {
   useViewer.closeElement(dialogName)
 }
+
+const openDialog = () => {
+  close()
+  useViewer.openElement('certificateViewerDialog')
+}
 </script>
 
 <style lang="scss">

+ 1 - 1
packages/webview/src/components/DocumentContainer/DocumentContainer.vue

@@ -51,7 +51,7 @@
   <SelectSignTypeDialog />
   <SignatureAppearanceDialog />
   <SignatureDetailsDialog />
-  <CertificationDetailsDialog />
+  <CertificationViewerDialog />
   <DeleteSignatureDialog />
   <div v-if="loading && loadingPercent < 100" class="loading-state">{{ $t('loading') }}...</div>
   <div v-show="loadingPercent <= 0 && !load && activePanelTab !== 'COMPARISON' && ['compare', 'document'].includes(toolMode)" class="upload-container">

+ 7 - 0
packages/webview/src/components/Icon/FailedIcon.vue

@@ -0,0 +1,7 @@
+<template>
+  <svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <path d="M17.5 10.5C17.5 14.6421 14.1421 18 10 18C5.85786 18 2.5 14.6421 2.5 10.5C2.5 6.35786 5.85786 3 10 3C14.1421 3 17.5 6.35786 17.5 10.5Z" fill="#FF6666"/>
+    <path d="M12 8.5L8 12.5" stroke="white" stroke-width="1.5" stroke-linecap="square" stroke-linejoin="round"/>
+    <path d="M8 8.5L12 12.5" stroke="white" stroke-width="1.5" stroke-linecap="square" stroke-linejoin="round"/>
+  </svg>
+</template>

+ 5 - 0
packages/webview/src/components/Icon/SuccessIcon.vue

@@ -0,0 +1,5 @@
+<template>
+  <svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M10 18C14.1421 18 17.5 14.6421 17.5 10.5C17.5 6.35786 14.1421 3 10 3C5.85786 3 2.5 6.35786 2.5 10.5C2.5 14.6421 5.85786 18 10 18ZM9.74283 13.4801L13.9095 8.48014L12.7572 7.51986L9.11627 11.8889L7.197 9.96967L6.13634 11.0303L8.63634 13.5303L9.21707 14.1111L9.74283 13.4801Z" fill="#3CCD75"/>
+  </svg>
+</template>

+ 1 - 1
packages/webview/src/components/SignatureContainer/SignatureContainer.vue

@@ -26,7 +26,7 @@
             </template>
             <div class="drop-down">
               <div class="drop-item" @click="openDialog('signatureDetailsDialog')">{{ $t('leftPanel.signatureDetails') }}</div>
-              <div class="drop-item" @click="openDialog('certificationDetailsDialog')">{{ $t('leftPanel.certificationDetails') }}</div>
+              <div class="drop-item" @click="openDialog('certificateViewerDialog')">{{ $t('leftPanel.certificationDetails') }}</div>
               <div class="drop-item" @click="openDialog('deleteConfirmDialog')">{{ $t('delete') }}</div>
             </div>
           </n-popover>

+ 1 - 0
packages/webview/src/components/SignatureToolBar/SignatureToolBar.vue

@@ -50,6 +50,7 @@
   }
 
   const verifyDigitalSign = () => {
+    changeActiveTool('')
     console.log('verifyDigitalSign')
   }
 </script>

+ 2 - 2
packages/webview/src/stores/modules/viewer.js

@@ -44,7 +44,7 @@ export const useViewerStore = defineStore({
       selectSignTypeDialog: false,
       signatureAppearanceDialog: false,
       signatureDetailsDialog: false,
-      certificationDetailsDialog: false,
+      certificateViewerDialog: false,
       deleteSignatureDialog: false
     },
     activeElementsTab: {
@@ -386,7 +386,7 @@ export const useViewerStore = defineStore({
         selectSignTypeDialog: false,
         signatureAppearanceDialog: false,
         signatureDetailsDialog: false,
-        certificationDetailsDialog: false,
+        certificateViewerDialog: false,
         deleteSignatureDialog: false
       },
       this.activeElementsTab = {