KMPDFDigitalSignViewController.swift 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. //
  2. // KMPDFDigitalSignViewController.swift
  3. // PDF Reader Pro Edition
  4. //
  5. // Created by Niehaoyu on 2023/10/19.
  6. //
  7. import Cocoa
  8. class KMPDFDigitalSignViewController: NSViewController, CPDFViewDelegate, CPDFDigtalViewDelegate {
  9. @IBOutlet weak var contendView: NSView!
  10. @IBOutlet weak var headerView: NSView!
  11. @IBOutlet weak var tipLabel: NSTextField!
  12. @IBOutlet weak var exitBox: NSBox!
  13. @IBOutlet weak var exitButton: KMCustomButton!
  14. @IBOutlet weak var saveBox: NSBox!
  15. @IBOutlet weak var saveButton: KMCustomButton!
  16. @IBOutlet weak var stateBGView: NSView!
  17. @IBOutlet weak var stateLbl: NSTextField!
  18. @IBOutlet weak var stateButton: NSButton!
  19. @IBOutlet weak var pdfContendView: NSView!
  20. @IBOutlet weak var contentTopConst: NSLayoutConstraint!
  21. var editWidgeAnnotation: CPDFSignatureWidgetAnnotation!
  22. var stateVC: CDSignatureCertificateStateViewController!
  23. @objc var scaleFactor: CGFloat = 0
  24. @objc var url: URL!
  25. @objc var password = String()
  26. @objc var currentPageIndex: Int = 0
  27. var signatures = NSArray()
  28. var type:CPromptSignaturesState = .failure
  29. @objc var titleChangeBlock: ((_ title: String, _ pageIndex: NSInteger)->Void)?
  30. @objc var buttonActionBlock: ((_ actionType: DSignatureActionType, _ isChanged: Bool)->Void)?
  31. var pdfView: CPDFDigtalView!
  32. override func viewDidAppear() {
  33. super.viewDidAppear()
  34. let contextString = NSLocalizedString("Please box an area for the signature to be added, then you can add a new digital signature.", comment: "")
  35. _ = CustomAlertView.alertView(message: contextString, fromView: self.view, withStyle: .black)
  36. }
  37. override func viewDidLoad() {
  38. super.viewDidLoad()
  39. // Do view setup here.
  40. self.headerView.wantsLayer = true
  41. self.headerView.layer?.backgroundColor = KMAppearance.Interactive.a0Color().cgColor
  42. self.tipLabel.stringValue = NSLocalizedString("You are Under Digital Sign Mode", comment: "")
  43. self.exitBox.borderColor = KMAppearance.Layout.w70Color()
  44. self.exitBox.borderWidth = 1.0
  45. self.exitButton.title = NSLocalizedString("Exit", comment: "")
  46. self.saveBox.fillColor = NSColor.white
  47. self.saveButton.title = NSLocalizedString("Exit", comment: "")
  48. self.saveButton.setTitleColor(KMAppearance.Interactive.a0Color())
  49. self.exitBox.isHidden = true
  50. self.pdfView = CPDFDigtalView.init(frame: self.pdfContendView.bounds)
  51. self.pdfView.autoresizingMask = [.width, .height]
  52. let document = CPDFDocument.init(url: self.url)
  53. if self.password.count > 0 {
  54. document?.unlock(withPassword: self.password)
  55. }
  56. self.pdfView.delegate = self
  57. self.pdfView.document = document
  58. self.pdfView.autoScales = true
  59. self.pdfView.pdfListViewDelegate = self
  60. self.pdfContendView.addSubview(self.pdfView)
  61. self.stateBGView.wantsLayer = true
  62. self.stateBGView.layer?.backgroundColor = KMAppearance.Else.textHighlightColor().cgColor
  63. self.stateLbl.textColor = NSColor.labelColor
  64. self.reloadState()
  65. NotificationCenter.default.addObserver(self, selector: #selector(signatureStateChangeNoti), name: NSNotification.Name(rawValue: "CSignatureTrustCerDidChangeNotification"), object: nil)
  66. }
  67. //MARK: Public Method
  68. func reloadState() {
  69. if self.pdfView.signatures.count > 0 {
  70. self.stateBGView.isHidden = false
  71. self.contentTopConst.constant = 44
  72. } else {
  73. self.stateBGView.isHidden = true
  74. self.contentTopConst.constant = 0
  75. }
  76. self.signatures = self.pdfView.signatures! as NSArray
  77. var isSignVerified = false
  78. var isCertTrusted = false
  79. for item in self.signatures {
  80. let signature: CPDFSignature = item as! CPDFSignature
  81. if signature.signers != nil {
  82. let signer = signature.signers.first
  83. if signer?.isCertTrusted == false {
  84. isCertTrusted = false
  85. break
  86. } else {
  87. isCertTrusted = true
  88. }
  89. }
  90. }
  91. for item in self.signatures {
  92. let signature: CPDFSignature = item as! CPDFSignature
  93. if signature.signers != nil {
  94. let signer = signature.signers.first
  95. if signer?.isSignVerified == false {
  96. isSignVerified = false
  97. break
  98. } else {
  99. isSignVerified = true
  100. }
  101. }
  102. }
  103. self.stateBGView.isHidden = false
  104. if (isSignVerified && isCertTrusted) {
  105. self.type = .Success;
  106. } else if(isSignVerified && !isCertTrusted) {
  107. self.type = .Unknown;
  108. } else {
  109. self.type = .failure;
  110. }
  111. if (.Success == self.type) {
  112. self.stateButton.image = NSImage(named: "ImageNameSigntureVerifySuccess")
  113. self.stateLbl.stringValue = NSLocalizedString("Signature is valid.", comment: "")
  114. } else if(.Unknown == self.type) {
  115. self.stateButton.image = NSImage(named: "ImageNameSigntureTrustedFailure")
  116. if(self.signatures.count > 1) {
  117. self.stateLbl.stringValue = NSLocalizedString("At least one signature is invalid.", comment: "")
  118. } else {
  119. self.stateLbl.stringValue = NSLocalizedString("Signature is invalid", comment: "")
  120. }
  121. } else {
  122. self.stateButton.image = NSImage(named: "ImageNameSigntureVerifyFailure")
  123. if(self.signatures.count > 1) {
  124. self.stateLbl.stringValue = NSLocalizedString("At least one signature is invalid.", comment: "")
  125. } else {
  126. self.stateLbl.stringValue = NSLocalizedString("Signature is invalid", comment: "")
  127. }
  128. }
  129. }
  130. func writeSignatureToWidget(_ widget: CPDFSignatureWidgetAnnotation, _ path: String, _ password: String, _ config: CPDFSignatureConfig, _ isLock: Bool) ->() {
  131. let fileName = self.pdfView.document.documentURL?.lastPathComponent
  132. let fileNameWithoutExtension = URL(fileURLWithPath: fileName!).deletingPathExtension().lastPathComponent
  133. let outputSavePanel = NSSavePanel()
  134. outputSavePanel.directoryURL = self.pdfView.document.documentURL.deletingLastPathComponent()
  135. outputSavePanel.title = NSLocalizedString("", comment: "Save as PDF")
  136. outputSavePanel.allowedFileTypes = ["pdf"]
  137. outputSavePanel.nameFieldStringValue = fileNameWithoutExtension + "_" + NSLocalizedString("Signed", comment: "")
  138. let result = outputSavePanel.runModal()
  139. if result == .OK {
  140. let contentArr = NSMutableArray()
  141. var locationStr = ""
  142. var reasonStr = NSLocalizedString("none", comment: "")
  143. for item in config.contents {
  144. if item.key == NSLocalizedString("Reason", comment: "") {
  145. if item.value == NSLocalizedString("<your signing reason here>", comment: "") {
  146. item.value = " " + NSLocalizedString("none", comment: "")
  147. }
  148. reasonStr = item.value
  149. } else if item.key == NSLocalizedString("Location", comment: "") {
  150. if item.value == NSLocalizedString("<your signing location here>", comment: "") {
  151. item.value = " "
  152. }
  153. locationStr = item.value
  154. }
  155. contentArr.add(item)
  156. }
  157. config.contents = contentArr as? [CPDFSignatureConfigItem]
  158. widget.signAppearanceConfig(config)
  159. let success = self.pdfView.document.writeSignature(to: outputSavePanel.url, withWidget: widget, pkcs12Cert: path, password: password, location: locationStr, reason: reasonStr, permissions: .forbidChange)
  160. widget.removeSignature()
  161. if success {
  162. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
  163. NSDocumentController.shared.openDocument(withContentsOf: outputSavePanel.url!, display: true) { document, documentWasAlreadyOpen, error in
  164. if error != nil {
  165. NSApp.presentError(error!)
  166. return
  167. }
  168. }
  169. }
  170. } else {
  171. let alert = NSAlert.init()
  172. alert.messageText = NSLocalizedString("Save failed!", comment: "")
  173. alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
  174. alert.runModal()
  175. }
  176. widget.page.removeAnnotation(widget)
  177. self.pdfView.setNeedsDisplayAnnotationViewFor(widget.page)
  178. } else {
  179. widget.page.removeAnnotation(widget)
  180. self.pdfView.setNeedsDisplayAnnotationViewFor(widget.page)
  181. }
  182. }
  183. //MARK: Setter
  184. //MARK: IBAction
  185. @IBAction func exitButtonAction(_ sender: NSButton) {
  186. }
  187. @IBAction func saveButtonAction(_ sender: NSButton) {
  188. // var documentArray = NSDocumentController.shared.documents
  189. var didFileEdit = false
  190. // for i in 0...documentArray.count-1 {
  191. // let document = documentArray[i]
  192. // if document.fileURL!.path == self.pdfView.document.documentURL.path {
  193. // didFileEdit = document.isDocumentEdited
  194. //
  195. // break
  196. // }
  197. // }
  198. guard let callBack = self.buttonActionBlock else {
  199. return
  200. }
  201. callBack(.cancel, didFileEdit)
  202. }
  203. //MARK: CPDFViewDelegate
  204. func pdfViewDocumentDidLoaded(_ pdfView: CPDFView!) {
  205. self.pdfView.go(toPageIndex: self.currentPageIndex, animated: true)
  206. }
  207. func pdfViewCurrentPageDidChanged(_ pdfView: CPDFView!) {
  208. let fileName = pdfView.document.documentURL.deletingPathExtension().lastPathComponent
  209. let title = String(format: "%@ (page %ld / %ld)", fileName, pdfView.currentPageIndex+1, pdfView.document.pageCount)
  210. self.currentPageIndex = pdfView.currentPageIndex
  211. guard let callBack = self.titleChangeBlock else {
  212. return
  213. }
  214. callBack(title, self.currentPageIndex)
  215. }
  216. func pdfListViewAddAnnotation(_ pdfListView: CPDFDigtalView!, forAdd annotation: CPDFAnnotation!, in pdfPage: CPDFPage!) {
  217. let widget = CPDFSignatureWidgetAnnotation.init(PDFListViewNoteWith: self.pdfView.document)
  218. widget.bounds = CGRectMake(-1000, -1000, 545, 178);
  219. annotation.page.addAnnotation(widget)
  220. let configWindowVC = DSignatureConfigWindowController.init(windowNibName: "DSignatureConfigWindowController")
  221. configWindowVC.viewType = .fileList;
  222. configWindowVC.appearanceWidget = widget;
  223. configWindowVC.isCreatDS = false
  224. configWindowVC.complentionHandle = {isSign, dic, config, isLock in
  225. widget.page.removeAnnotation(widget)
  226. if isSign {
  227. if (dic.object(forKey: SAVEFILEPATH_KEY) != nil) {
  228. let p12Path = dic.object(forKey: SAVEFILEPATH_KEY) as! String
  229. let password = dic.object(forKey: PASSWORD_KEY)
  230. if p12Path.count > 0 {
  231. self.writeSignatureToWidget(annotation as! CPDFSignatureWidgetAnnotation, p12Path, password as! String, config, isLock)
  232. }
  233. }
  234. }
  235. }
  236. configWindowVC.actionBlock = { controller, type in
  237. if (type == .cancel) {
  238. NSApplication.shared.stopModal()
  239. controller.window?.orderOut(nil)
  240. controller.window?.close()
  241. annotation.page.removeAnnotation(annotation)
  242. widget.page.removeAnnotation(widget)
  243. self.pdfView.setNeedsDisplayAnnotationViewFor(annotation.page)
  244. } else if (type == .confirm) {
  245. NSApplication.shared.stopModal()
  246. controller.window?.orderOut(nil)
  247. controller.window?.close()
  248. }
  249. }
  250. configWindowVC.window?.center()
  251. NSApplication.shared.runModal(for: configWindowVC.window!)
  252. }
  253. func pdfListViewEditAnnotation(_ pdfListView: CPDFDigtalView!, for anotation: CPDFAnnotation!) {
  254. if anotation.className == CPDFSignatureWidgetAnnotation.className() {
  255. let signatureWidget = anotation as! CPDFSignatureWidgetAnnotation
  256. var signature = signatureWidget.signature()
  257. if signature == nil {
  258. return
  259. }
  260. if signature?.signers != nil {
  261. self.editWidgeAnnotation = signatureWidget
  262. self.popUpSignatureWidgetState(signature!, self.pdfView)
  263. } else if signatureWidget.isSigned() {
  264. // self.signElectronicSignature(signatureWidget)
  265. } else {
  266. }
  267. //// __block WindowController *weakself = self;
  268. // CPDFSignatureWidgetAnnotation *signatureWidget = (CPDFSignatureWidgetAnnotation *)annotation;
  269. // CPDFSignature *signature = [signatureWidget signature];
  270. // if (signature.signers.count > 0) {
  271. // [self popUpSignatureWidgetState:signature];
  272. // } else if (signatureWidget.isSigned) {
  273. // [self signElectronicSignature:signatureWidget];
  274. // } else {
  275. // CDSignatureSignTypeWindowController *signType = [[CDSignatureSignTypeWindowController alloc] init];
  276. // signType.callback = ^(CDSignType type) {
  277. // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  278. // if(type == CDSignType_ElectronicSignature) {
  279. // [weakself signElectronicSignature:signatureWidget];
  280. // } else {
  281. // [weakself signDigitalSignature:signatureWidget];
  282. // }
  283. // });
  284. // };
  285. // [signType startModal:nil];
  286. // [signType release];
  287. // }
  288. }
  289. }
  290. func popUpSignatureWidgetState(_ signature: CPDFSignature, _ pdfListView: CPDFDigtalView) ->(){
  291. if self.stateVC == nil {
  292. self.stateVC = CDSignatureCertificateStateViewController.init()
  293. }
  294. self.stateVC.signature = signature
  295. self.stateVC.pdfListView = pdfListView
  296. self.stateVC.actionBlock = { stateVCSelf, actionType in
  297. if actionType == .cancel {
  298. stateVCSelf.dismiss(stateVCSelf)
  299. } else if actionType == .confirm {
  300. let signer = signature.signers.first
  301. let signatureDetail = DSignatureDetailsViewController.init()
  302. signatureDetail.certificates = (signer?.certificates)!
  303. signatureDetail.signature = signature
  304. signatureDetail.pdfListView = pdfListView
  305. stateVCSelf.presentAsSheet(signatureDetail)
  306. }
  307. }
  308. self.presentAsSheet(self.stateVC)
  309. self.stateVC.reloadData()
  310. }
  311. func signElectronicSignature(_ signatureWidgetAnnotation: CPDFSignatureWidgetAnnotation) -> () {
  312. // PDFCustomSignatureWindowController *signatureWindowController = [[PDFCustomSignatureWindowController alloc] init];
  313. // __block typeof(self) blockSelf = self;
  314. // [signatureWindowController beginSheetModalForWindow:[NSApp mainWindow] completionHandler:^(PDFSignature *signature){
  315. // if (signature) {
  316. // [signatureWidgetAnnotation signWithImage:signature.pathsImage];
  317. // [blockSelf.PDFListView setNeedsDisplayAnnotationViewForPage:signatureWidgetAnnotation.page];
  318. // }
  319. // }];
  320. // [signatureWindowController release];
  321. }
  322. //MARK: Notification
  323. @objc fileprivate func signatureStateChangeNoti() {
  324. let signatures = self.pdfView.document.signatures()!
  325. let tempArr = NSMutableArray()
  326. for signature in signatures {
  327. if signature.signers != nil {
  328. if signature.signers.count > 0 {
  329. signature.verifySignature(with: self.pdfView.document)
  330. tempArr.add(signature)
  331. }
  332. }
  333. }
  334. self.pdfView.signatures = tempArr as? [Any]
  335. self.reloadState()
  336. if self.stateVC != nil {
  337. let signatureWidget = self.editWidgeAnnotation!
  338. var signature = signatureWidget.signature()
  339. if signature == nil {
  340. return
  341. }
  342. self.stateVC.signature = signature
  343. self.stateVC.reloadData()
  344. }
  345. }
  346. }