Display widget signature
- but don't validate them for now; - Firefox will display a bar to warn that the signature validation is not supported (see https://bugzilla.mozilla.org/show_bug.cgi?id=854315) - almost all (all ?) pdf readers display signatures; - validation is done in edge but for now it's behind a pref.
This commit is contained in:
		
							parent
							
								
									6ddc297170
								
							
						
					
					
						commit
						5875ebb1ca
					
				| @ -15,5 +15,6 @@ | ||||
| # Chrome notification bar messages and buttons | ||||
| unsupported_feature=This PDF document might not be displayed correctly. | ||||
| unsupported_feature_forms=This PDF document contains forms. The filling of form fields is not supported. | ||||
| unsupported_feature_signatures=This PDF document contains digital signatures. Validation of signatures is not supported. | ||||
| open_with_different_viewer=Open With Different Viewer | ||||
| open_with_different_viewer.accessKey=o | ||||
|  | ||||
| @ -126,6 +126,8 @@ class AnnotationFactory { | ||||
|             return new ButtonWidgetAnnotation(parameters); | ||||
|           case "Ch": | ||||
|             return new ChoiceWidgetAnnotation(parameters); | ||||
|           case "Sig": | ||||
|             return new SignatureWidgetAnnotation(parameters); | ||||
|         } | ||||
|         warn( | ||||
|           `Unimplemented widget field type "${fieldType}", ` + | ||||
| @ -1151,15 +1153,6 @@ class WidgetAnnotation extends Annotation { | ||||
| 
 | ||||
|     data.readOnly = this.hasFieldFlag(AnnotationFieldFlag.READONLY); | ||||
|     data.hidden = this._hasFlag(data.annotationFlags, AnnotationFlag.HIDDEN); | ||||
| 
 | ||||
|     // Hide signatures because we cannot validate them, and unset the fieldValue
 | ||||
|     // since it's (most likely) a `Dict` which is non-serializable and will thus
 | ||||
|     // cause errors when sending annotations to the main-thread (issue 10347).
 | ||||
|     if (data.fieldType === "Sig") { | ||||
|       data.fieldValue = null; | ||||
|       this.setFlags(AnnotationFlag.HIDDEN); | ||||
|       data.hidden = true; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
| @ -1201,7 +1194,7 @@ class WidgetAnnotation extends Annotation { | ||||
|   getOperatorList(evaluator, task, renderForms, annotationStorage) { | ||||
|     // Do not render form elements on the canvas when interactive forms are
 | ||||
|     // enabled. The display layer is responsible for rendering them instead.
 | ||||
|     if (renderForms) { | ||||
|     if (renderForms && !(this instanceof SignatureWidgetAnnotation)) { | ||||
|       return Promise.resolve(new OperatorList()); | ||||
|     } | ||||
| 
 | ||||
| @ -1600,13 +1593,6 @@ class WidgetAnnotation extends Annotation { | ||||
|   } | ||||
| 
 | ||||
|   getFieldObject() { | ||||
|     if (this.data.fieldType === "Sig") { | ||||
|       return { | ||||
|         id: this.data.id, | ||||
|         value: null, | ||||
|         type: "signature", | ||||
|       }; | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
| @ -2203,6 +2189,25 @@ class ChoiceWidgetAnnotation extends WidgetAnnotation { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class SignatureWidgetAnnotation extends WidgetAnnotation { | ||||
|   constructor(params) { | ||||
|     super(params); | ||||
| 
 | ||||
|     // Unset the fieldValue since it's (most likely) a `Dict` which is
 | ||||
|     // non-serializable and will thus cause errors when sending annotations
 | ||||
|     // to the main-thread (issue 10347).
 | ||||
|     this.data.fieldValue = null; | ||||
|   } | ||||
| 
 | ||||
|   getFieldObject() { | ||||
|     return { | ||||
|       id: this.data.id, | ||||
|       value: null, | ||||
|       type: "signature", | ||||
|     }; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class TextAnnotation extends MarkupAnnotation { | ||||
|   constructor(parameters) { | ||||
|     const DEFAULT_ICON_SIZE = 22; // px
 | ||||
|  | ||||
| @ -828,7 +828,12 @@ class PDFDocument { | ||||
|   } | ||||
| 
 | ||||
|   get formInfo() { | ||||
|     const formInfo = { hasFields: false, hasAcroForm: false, hasXfa: false }; | ||||
|     const formInfo = { | ||||
|       hasFields: false, | ||||
|       hasAcroForm: false, | ||||
|       hasXfa: false, | ||||
|       hasSignatures: false, | ||||
|     }; | ||||
|     const acroForm = this.catalog.acroForm; | ||||
|     if (!acroForm) { | ||||
|       return shadow(this, "formInfo", formInfo); | ||||
| @ -854,9 +859,11 @@ class PDFDocument { | ||||
|       // the first bit of the `SigFlags` integer (see Table 219 in the
 | ||||
|       // specification).
 | ||||
|       const sigFlags = acroForm.get("SigFlags"); | ||||
|       const hasSignatures = !!(sigFlags & 0x1); | ||||
|       const hasOnlyDocumentSignatures = | ||||
|         !!(sigFlags & 0x1) && this._hasOnlyDocumentSignatures(fields); | ||||
|         hasSignatures && this._hasOnlyDocumentSignatures(fields); | ||||
|       formInfo.hasAcroForm = hasFields && !hasOnlyDocumentSignatures; | ||||
|       formInfo.hasSignatures = hasSignatures; | ||||
|     } catch (ex) { | ||||
|       if (ex instanceof MissingDataException) { | ||||
|         throw ex; | ||||
| @ -894,6 +901,7 @@ class PDFDocument { | ||||
|       IsAcroFormPresent: this.formInfo.hasAcroForm, | ||||
|       IsXFAPresent: this.formInfo.hasXfa, | ||||
|       IsCollectionPresent: !!this.catalog.collection, | ||||
|       IsSignaturesPresent: this.formInfo.hasSignatures, | ||||
|     }; | ||||
| 
 | ||||
|     let infoDict; | ||||
|  | ||||
| @ -315,6 +315,7 @@ const UNSUPPORTED_FEATURES = { | ||||
|   unknown: "unknown", | ||||
|   forms: "forms", | ||||
|   javaScript: "javaScript", | ||||
|   signatures: "signatures", | ||||
|   smask: "smask", | ||||
|   shadingPattern: "shadingPattern", | ||||
|   /** @deprecated unused */ | ||||
|  | ||||
							
								
								
									
										1
									
								
								test/pdfs/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								test/pdfs/.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -85,6 +85,7 @@ | ||||
| !issue9458.pdf | ||||
| !issue9655_reduced.pdf | ||||
| !issue9915_reduced.pdf | ||||
| !bug854315.pdf | ||||
| !issue9940.pdf | ||||
| !issue10388_reduced.pdf | ||||
| !issue10438_reduced.pdf | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								test/pdfs/bug854315.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								test/pdfs/bug854315.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -389,6 +389,12 @@ | ||||
|        "rounds": 1, | ||||
|        "type": "load" | ||||
|     }, | ||||
|     {  "id": "bug854315", | ||||
|        "file": "pdfs/bug854315.pdf", | ||||
|        "md5": "675754c07f71c068d2997905a5456f05", | ||||
|        "rounds": 1, | ||||
|        "type": "eq" | ||||
|     }, | ||||
|     {  "id": "bug868745", | ||||
|        "file": "pdfs/bug868745.pdf", | ||||
|        "md5": "86111ea5097dd7daffcdea891ad1b348", | ||||
|  | ||||
| @ -1212,6 +1212,7 @@ describe("api", function () { | ||||
|           expect(info.IsAcroFormPresent).toEqual(false); | ||||
|           expect(info.IsXFAPresent).toEqual(false); | ||||
|           expect(info.IsCollectionPresent).toEqual(false); | ||||
|           expect(info.IsSignaturesPresent).toEqual(false); | ||||
| 
 | ||||
|           expect(metadata instanceof Metadata).toEqual(true); | ||||
|           expect(metadata.get("dc:title")).toEqual("Basic API Test"); | ||||
| @ -1254,6 +1255,7 @@ describe("api", function () { | ||||
|           expect(info.IsAcroFormPresent).toEqual(false); | ||||
|           expect(info.IsXFAPresent).toEqual(false); | ||||
|           expect(info.IsCollectionPresent).toEqual(false); | ||||
|           expect(info.IsSignaturesPresent).toEqual(false); | ||||
| 
 | ||||
|           expect(metadata).toEqual(null); | ||||
|           expect(contentDispositionFilename).toEqual(null); | ||||
| @ -1282,6 +1284,7 @@ describe("api", function () { | ||||
|           expect(info.IsAcroFormPresent).toEqual(false); | ||||
|           expect(info.IsXFAPresent).toEqual(false); | ||||
|           expect(info.IsCollectionPresent).toEqual(false); | ||||
|           expect(info.IsSignaturesPresent).toEqual(false); | ||||
| 
 | ||||
|           expect(metadata).toEqual(null); | ||||
|           expect(contentDispositionFilename).toEqual(null); | ||||
|  | ||||
| @ -77,6 +77,7 @@ describe("document", function () { | ||||
|       const pdfDocument = getDocument(null); | ||||
|       expect(pdfDocument.formInfo).toEqual({ | ||||
|         hasAcroForm: false, | ||||
|         hasSignatures: false, | ||||
|         hasXfa: false, | ||||
|         hasFields: false, | ||||
|       }); | ||||
| @ -90,6 +91,7 @@ describe("document", function () { | ||||
|       let pdfDocument = getDocument(acroForm); | ||||
|       expect(pdfDocument.formInfo).toEqual({ | ||||
|         hasAcroForm: false, | ||||
|         hasSignatures: false, | ||||
|         hasXfa: false, | ||||
|         hasFields: false, | ||||
|       }); | ||||
| @ -98,6 +100,7 @@ describe("document", function () { | ||||
|       pdfDocument = getDocument(acroForm); | ||||
|       expect(pdfDocument.formInfo).toEqual({ | ||||
|         hasAcroForm: false, | ||||
|         hasSignatures: false, | ||||
|         hasXfa: true, | ||||
|         hasFields: false, | ||||
|       }); | ||||
| @ -106,6 +109,7 @@ describe("document", function () { | ||||
|       pdfDocument = getDocument(acroForm); | ||||
|       expect(pdfDocument.formInfo).toEqual({ | ||||
|         hasAcroForm: false, | ||||
|         hasSignatures: false, | ||||
|         hasXfa: false, | ||||
|         hasFields: false, | ||||
|       }); | ||||
| @ -114,6 +118,7 @@ describe("document", function () { | ||||
|       pdfDocument = getDocument(acroForm); | ||||
|       expect(pdfDocument.formInfo).toEqual({ | ||||
|         hasAcroForm: false, | ||||
|         hasSignatures: false, | ||||
|         hasXfa: true, | ||||
|         hasFields: false, | ||||
|       }); | ||||
| @ -127,6 +132,7 @@ describe("document", function () { | ||||
|       let pdfDocument = getDocument(acroForm); | ||||
|       expect(pdfDocument.formInfo).toEqual({ | ||||
|         hasAcroForm: false, | ||||
|         hasSignatures: false, | ||||
|         hasXfa: false, | ||||
|         hasFields: false, | ||||
|       }); | ||||
| @ -135,6 +141,7 @@ describe("document", function () { | ||||
|       pdfDocument = getDocument(acroForm); | ||||
|       expect(pdfDocument.formInfo).toEqual({ | ||||
|         hasAcroForm: true, | ||||
|         hasSignatures: false, | ||||
|         hasXfa: false, | ||||
|         hasFields: true, | ||||
|       }); | ||||
| @ -146,6 +153,7 @@ describe("document", function () { | ||||
|       pdfDocument = getDocument(acroForm); | ||||
|       expect(pdfDocument.formInfo).toEqual({ | ||||
|         hasAcroForm: true, | ||||
|         hasSignatures: false, | ||||
|         hasXfa: false, | ||||
|         hasFields: true, | ||||
|       }); | ||||
| @ -169,6 +177,7 @@ describe("document", function () { | ||||
|       pdfDocument = getDocument(acroForm, xref); | ||||
|       expect(pdfDocument.formInfo).toEqual({ | ||||
|         hasAcroForm: false, | ||||
|         hasSignatures: true, | ||||
|         hasXfa: false, | ||||
|         hasFields: true, | ||||
|       }); | ||||
|  | ||||
| @ -1583,6 +1583,11 @@ const PDFViewerApplication = { | ||||
|       this._delayedFallback(UNSUPPORTED_FEATURES.forms); | ||||
|     } | ||||
| 
 | ||||
|     if (info.IsSignaturesPresent) { | ||||
|       console.warn("Warning: Digital signatures validation is not supported"); | ||||
|       this.fallback(UNSUPPORTED_FEATURES.signatures); | ||||
|     } | ||||
| 
 | ||||
|     // Telemetry labels must be C++ variable friendly.
 | ||||
|     let versionId = "other"; | ||||
|     if (KNOWN_VERSIONS.includes(info.PDFFormatVersion)) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user