KMPDFDigitalSignViewController.swift 17 KB

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