diff --git a/Podfile b/Podfile index 13ea5b9..a6818c3 100644 --- a/Podfile +++ b/Podfile @@ -2,7 +2,6 @@ platform :ios, '10.2' use_frameworks! target 'passKit' do - pod 'ObjectivePGP', :git => 'https://github.com/krzyzanowskim/ObjectivePGP.git', :tag => '0.14.0' target 'pass' do inherit! :search_paths end diff --git a/go/dist/Gopenpgpwrapper.framework/Gopenpgpwrapper b/go/dist/Gopenpgpwrapper.framework/Gopenpgpwrapper new file mode 100644 index 0000000..e2eea6a Binary files /dev/null and b/go/dist/Gopenpgpwrapper.framework/Gopenpgpwrapper differ diff --git a/go/dist/Gopenpgpwrapper.framework/Headers/Gopenpgpwrapper.h b/go/dist/Gopenpgpwrapper.framework/Headers/Gopenpgpwrapper.h new file mode 100644 index 0000000..ab2d6f7 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Headers/Gopenpgpwrapper.h @@ -0,0 +1,13 @@ + +// Objective-C API for talking to the following Go packages +// +// github.com/ZortacDev/GopenPGPWrapper/go/gopenpgpwrapper +// +// File is generated by gomobile bind. Do not edit. +#ifndef __Gopenpgpwrapper_FRAMEWORK_H__ +#define __Gopenpgpwrapper_FRAMEWORK_H__ + +#include "Gopenpgpwrapper.objc.h" +#include "Universe.objc.h" + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Headers/Gopenpgpwrapper.objc.h b/go/dist/Gopenpgpwrapper.framework/Headers/Gopenpgpwrapper.objc.h new file mode 100644 index 0000000..e3cd9bb --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Headers/Gopenpgpwrapper.objc.h @@ -0,0 +1,29 @@ +// Objective-C API for talking to github.com/ZortacDev/GopenPGPWrapper/go/gopenpgpwrapper Go package. +// gobind -lang=objc github.com/ZortacDev/GopenPGPWrapper/go/gopenpgpwrapper +// +// File is generated by gobind. Do not edit. + +#ifndef __Gopenpgpwrapper_H__ +#define __Gopenpgpwrapper_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@class GopenpgpwrapperKey; + +@interface GopenpgpwrapperKey : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +- (NSData* _Nullable)decrypt:(NSData* _Nullable)ciphertext passphrase:(NSString* _Nullable)passphrase; +- (NSData* _Nullable)encrypt:(NSData* _Nullable)plaintext armor:(BOOL)armor; +- (NSString* _Nonnull)getKeyID; +@end + +FOUNDATION_EXPORT GopenpgpwrapperKey* _Nullable GopenpgpwrapperReadKey(NSData* _Nullable data); + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Headers/Universe.objc.h b/go/dist/Gopenpgpwrapper.framework/Headers/Universe.objc.h new file mode 100644 index 0000000..019e750 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Headers/Universe.objc.h @@ -0,0 +1,29 @@ +// Objective-C API for talking to Go package. +// gobind -lang=objc +// +// File is generated by gobind. Do not edit. + +#ifndef __Universe_H__ +#define __Universe_H__ + +@import Foundation; +#include "ref.h" + +@protocol Universeerror; +@class Universeerror; + +@protocol Universeerror +- (NSString* _Nonnull)error; +@end + +@class Universeerror; + +@interface Universeerror : NSError { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (NSString* _Nonnull)error; +@end + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Headers/ref.h b/go/dist/Gopenpgpwrapper.framework/Headers/ref.h new file mode 100644 index 0000000..b8036a4 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Headers/ref.h @@ -0,0 +1,35 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef __GO_REF_HDR__ +#define __GO_REF_HDR__ + +#include + +// GoSeqRef is an object tagged with an integer for passing back and +// forth across the language boundary. A GoSeqRef may represent either +// an instance of a Go object, or an Objective-C object passed to Go. +// The explicit allocation of a GoSeqRef is used to pin a Go object +// when it is passed to Objective-C. The Go seq package maintains a +// reference to the Go object in a map keyed by the refnum along with +// a reference count. When the reference count reaches zero, the Go +// seq package will clear the corresponding entry in the map. +@interface GoSeqRef : NSObject { +} +@property(readonly) int32_t refnum; +@property(strong) id obj; // NULL when representing a Go object. + +// new GoSeqRef object to proxy a Go object. The refnum must be +// provided from Go side. +- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj; + +- (int32_t)incNum; + +@end + +@protocol goSeqRefInterface +-(GoSeqRef*) _ref; +@end + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Modules/module.modulemap b/go/dist/Gopenpgpwrapper.framework/Modules/module.modulemap new file mode 100644 index 0000000..b388a7d --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Modules/module.modulemap @@ -0,0 +1,8 @@ +framework module "Gopenpgpwrapper" { + header "ref.h" + header "Gopenpgpwrapper.objc.h" + header "Universe.objc.h" + header "Gopenpgpwrapper.h" + + export * +} \ No newline at end of file diff --git a/go/dist/Gopenpgpwrapper.framework/Resources/Info.plist b/go/dist/Gopenpgpwrapper.framework/Resources/Info.plist new file mode 100644 index 0000000..0d1a4b8 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Resources/Info.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/A/Gopenpgpwrapper b/go/dist/Gopenpgpwrapper.framework/Versions/A/Gopenpgpwrapper new file mode 100644 index 0000000..e2eea6a Binary files /dev/null and b/go/dist/Gopenpgpwrapper.framework/Versions/A/Gopenpgpwrapper differ diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/Gopenpgpwrapper.h b/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/Gopenpgpwrapper.h new file mode 100644 index 0000000..ab2d6f7 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/Gopenpgpwrapper.h @@ -0,0 +1,13 @@ + +// Objective-C API for talking to the following Go packages +// +// github.com/ZortacDev/GopenPGPWrapper/go/gopenpgpwrapper +// +// File is generated by gomobile bind. Do not edit. +#ifndef __Gopenpgpwrapper_FRAMEWORK_H__ +#define __Gopenpgpwrapper_FRAMEWORK_H__ + +#include "Gopenpgpwrapper.objc.h" +#include "Universe.objc.h" + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/Gopenpgpwrapper.objc.h b/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/Gopenpgpwrapper.objc.h new file mode 100644 index 0000000..e3cd9bb --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/Gopenpgpwrapper.objc.h @@ -0,0 +1,29 @@ +// Objective-C API for talking to github.com/ZortacDev/GopenPGPWrapper/go/gopenpgpwrapper Go package. +// gobind -lang=objc github.com/ZortacDev/GopenPGPWrapper/go/gopenpgpwrapper +// +// File is generated by gobind. Do not edit. + +#ifndef __Gopenpgpwrapper_H__ +#define __Gopenpgpwrapper_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@class GopenpgpwrapperKey; + +@interface GopenpgpwrapperKey : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +- (NSData* _Nullable)decrypt:(NSData* _Nullable)ciphertext passphrase:(NSString* _Nullable)passphrase; +- (NSData* _Nullable)encrypt:(NSData* _Nullable)plaintext armor:(BOOL)armor; +- (NSString* _Nonnull)getKeyID; +@end + +FOUNDATION_EXPORT GopenpgpwrapperKey* _Nullable GopenpgpwrapperReadKey(NSData* _Nullable data); + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/Universe.objc.h b/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/Universe.objc.h new file mode 100644 index 0000000..019e750 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/Universe.objc.h @@ -0,0 +1,29 @@ +// Objective-C API for talking to Go package. +// gobind -lang=objc +// +// File is generated by gobind. Do not edit. + +#ifndef __Universe_H__ +#define __Universe_H__ + +@import Foundation; +#include "ref.h" + +@protocol Universeerror; +@class Universeerror; + +@protocol Universeerror +- (NSString* _Nonnull)error; +@end + +@class Universeerror; + +@interface Universeerror : NSError { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (NSString* _Nonnull)error; +@end + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/ref.h b/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/ref.h new file mode 100644 index 0000000..b8036a4 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/A/Headers/ref.h @@ -0,0 +1,35 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef __GO_REF_HDR__ +#define __GO_REF_HDR__ + +#include + +// GoSeqRef is an object tagged with an integer for passing back and +// forth across the language boundary. A GoSeqRef may represent either +// an instance of a Go object, or an Objective-C object passed to Go. +// The explicit allocation of a GoSeqRef is used to pin a Go object +// when it is passed to Objective-C. The Go seq package maintains a +// reference to the Go object in a map keyed by the refnum along with +// a reference count. When the reference count reaches zero, the Go +// seq package will clear the corresponding entry in the map. +@interface GoSeqRef : NSObject { +} +@property(readonly) int32_t refnum; +@property(strong) id obj; // NULL when representing a Go object. + +// new GoSeqRef object to proxy a Go object. The refnum must be +// provided from Go side. +- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj; + +- (int32_t)incNum; + +@end + +@protocol goSeqRefInterface +-(GoSeqRef*) _ref; +@end + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/A/Modules/module.modulemap b/go/dist/Gopenpgpwrapper.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..b388a7d --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,8 @@ +framework module "Gopenpgpwrapper" { + header "ref.h" + header "Gopenpgpwrapper.objc.h" + header "Universe.objc.h" + header "Gopenpgpwrapper.h" + + export * +} \ No newline at end of file diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/A/Resources/Info.plist b/go/dist/Gopenpgpwrapper.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..0d1a4b8 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/Current/Gopenpgpwrapper b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Gopenpgpwrapper new file mode 100644 index 0000000..e2eea6a Binary files /dev/null and b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Gopenpgpwrapper differ diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/Gopenpgpwrapper.h b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/Gopenpgpwrapper.h new file mode 100644 index 0000000..ab2d6f7 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/Gopenpgpwrapper.h @@ -0,0 +1,13 @@ + +// Objective-C API for talking to the following Go packages +// +// github.com/ZortacDev/GopenPGPWrapper/go/gopenpgpwrapper +// +// File is generated by gomobile bind. Do not edit. +#ifndef __Gopenpgpwrapper_FRAMEWORK_H__ +#define __Gopenpgpwrapper_FRAMEWORK_H__ + +#include "Gopenpgpwrapper.objc.h" +#include "Universe.objc.h" + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/Gopenpgpwrapper.objc.h b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/Gopenpgpwrapper.objc.h new file mode 100644 index 0000000..e3cd9bb --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/Gopenpgpwrapper.objc.h @@ -0,0 +1,29 @@ +// Objective-C API for talking to github.com/ZortacDev/GopenPGPWrapper/go/gopenpgpwrapper Go package. +// gobind -lang=objc github.com/ZortacDev/GopenPGPWrapper/go/gopenpgpwrapper +// +// File is generated by gobind. Do not edit. + +#ifndef __Gopenpgpwrapper_H__ +#define __Gopenpgpwrapper_H__ + +@import Foundation; +#include "ref.h" +#include "Universe.objc.h" + + +@class GopenpgpwrapperKey; + +@interface GopenpgpwrapperKey : NSObject { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (nonnull instancetype)init; +- (NSData* _Nullable)decrypt:(NSData* _Nullable)ciphertext passphrase:(NSString* _Nullable)passphrase; +- (NSData* _Nullable)encrypt:(NSData* _Nullable)plaintext armor:(BOOL)armor; +- (NSString* _Nonnull)getKeyID; +@end + +FOUNDATION_EXPORT GopenpgpwrapperKey* _Nullable GopenpgpwrapperReadKey(NSData* _Nullable data); + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/Universe.objc.h b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/Universe.objc.h new file mode 100644 index 0000000..019e750 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/Universe.objc.h @@ -0,0 +1,29 @@ +// Objective-C API for talking to Go package. +// gobind -lang=objc +// +// File is generated by gobind. Do not edit. + +#ifndef __Universe_H__ +#define __Universe_H__ + +@import Foundation; +#include "ref.h" + +@protocol Universeerror; +@class Universeerror; + +@protocol Universeerror +- (NSString* _Nonnull)error; +@end + +@class Universeerror; + +@interface Universeerror : NSError { +} +@property(strong, readonly) _Nonnull id _ref; + +- (nonnull instancetype)initWithRef:(_Nonnull id)ref; +- (NSString* _Nonnull)error; +@end + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/ref.h b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/ref.h new file mode 100644 index 0000000..b8036a4 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Headers/ref.h @@ -0,0 +1,35 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef __GO_REF_HDR__ +#define __GO_REF_HDR__ + +#include + +// GoSeqRef is an object tagged with an integer for passing back and +// forth across the language boundary. A GoSeqRef may represent either +// an instance of a Go object, or an Objective-C object passed to Go. +// The explicit allocation of a GoSeqRef is used to pin a Go object +// when it is passed to Objective-C. The Go seq package maintains a +// reference to the Go object in a map keyed by the refnum along with +// a reference count. When the reference count reaches zero, the Go +// seq package will clear the corresponding entry in the map. +@interface GoSeqRef : NSObject { +} +@property(readonly) int32_t refnum; +@property(strong) id obj; // NULL when representing a Go object. + +// new GoSeqRef object to proxy a Go object. The refnum must be +// provided from Go side. +- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj; + +- (int32_t)incNum; + +@end + +@protocol goSeqRefInterface +-(GoSeqRef*) _ref; +@end + +#endif diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/Current/Modules/module.modulemap b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Modules/module.modulemap new file mode 100644 index 0000000..b388a7d --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Modules/module.modulemap @@ -0,0 +1,8 @@ +framework module "Gopenpgpwrapper" { + header "ref.h" + header "Gopenpgpwrapper.objc.h" + header "Universe.objc.h" + header "Gopenpgpwrapper.h" + + export * +} \ No newline at end of file diff --git a/go/dist/Gopenpgpwrapper.framework/Versions/Current/Resources/Info.plist b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Resources/Info.plist new file mode 100644 index 0000000..0d1a4b8 --- /dev/null +++ b/go/dist/Gopenpgpwrapper.framework/Versions/Current/Resources/Info.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/go/src/gopenpgpwrapper.go b/go/src/gopenpgpwrapper.go new file mode 100644 index 0000000..1524bfb --- /dev/null +++ b/go/src/gopenpgpwrapper.go @@ -0,0 +1,84 @@ +package gopenpgpwrapper // import "gopenpgpwrapper" + +import ( + "bytes" + "io" + "io/ioutil" + + "github.com/ProtonMail/gopenpgp/crypto" + "github.com/ProtonMail/gopenpgp/armor" +) + +type Key struct { + kr crypto.KeyRing +} + +func (k *Key) GetKeyID() string { + return k.kr.FirstKeyID +} + +func (k *Key) Encrypt(plaintext []byte, armor bool) []byte { + var b bytes.Buffer + var w io.WriteCloser + if armor { + wr, err := k.kr.EncryptArmored(&b, nil) + if err != nil { + return nil + } + w = wr + } else { + wr, err := k.kr.Encrypt(&b, nil, "", false) + if err != nil { + return nil + } + + w = wr + } + + if _, err := w.Write(plaintext); err != nil { + return nil + } + + if err := w.Close(); err != nil { + return nil + } + + return b.Bytes() +} + +func (k Key) Decrypt(ciphertext []byte, passphrase string) []byte { + unarmored, err := armor.Unarmor(string(ciphertext)) + if err != nil { + // Assume ciphertext is already in binary format + unarmored = ciphertext + } + + err = k.kr.Unlock([]byte(passphrase)) + if err != nil { + return nil + } + + r, _, err := k.kr.Decrypt(bytes.NewReader(unarmored)) + if err != nil { + return nil + } + + if b, err := ioutil.ReadAll(r); err != nil { + return nil + } else { + return b + } +} + +func ReadKey(data []byte) *Key { + kr, err := crypto.ReadArmoredKeyRing(bytes.NewReader(data)) + if err != nil { + // Assume keyring is in binary form + kr, err = crypto.ReadKeyRing(bytes.NewReader(data)) + if err != nil { + return nil + } + } + + return &Key{kr: *kr} +} diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj index 0f8195e..f44e01f 100644 --- a/pass.xcodeproj/project.pbxproj +++ b/pass.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 1154BEDD229AC00F00454075 /* Gopenpgpwrapper.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1154BEDB229AC00F00454075 /* Gopenpgpwrapper.framework */; }; 18F19A67B0C07F13C17169E0 /* Pods_pass.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A5620D17DF5E86B61761D0E /* Pods_pass.framework */; }; 23B82F0228254275DBA609E7 /* Pods_passExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B975797E0F0B7476CADD6A7D /* Pods_passExtension.framework */; }; 300713C52219D54100F553AC /* AutoCellHeightUITableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 300713C42219D54100F553AC /* AutoCellHeightUITableViewController.swift */; }; @@ -207,6 +208,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 1154BEDB229AC00F00454075 /* Gopenpgpwrapper.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Gopenpgpwrapper.framework; path = go/dist/Gopenpgpwrapper.framework; sourceTree = ""; }; 300713C42219D54100F553AC /* AutoCellHeightUITableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCellHeightUITableViewController.swift; sourceTree = ""; }; 301F6462216162550071A4CE /* AdditionField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdditionField.swift; sourceTree = ""; }; 301F6467216165290071A4CE /* ConstantsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstantsTest.swift; sourceTree = ""; }; @@ -373,6 +375,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 1154BEDD229AC00F00454075 /* Gopenpgpwrapper.framework in Frameworks */, 61326CDA7A73757FB68DCB04 /* Pods_passKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -413,6 +416,7 @@ files = ( A239F5902158C07D00576CBF /* AuthenticationServices.framework in Frameworks */, A260758D1EEC6F34005DB03E /* passKit.framework in Frameworks */, + 1154BEDC229AC00F00454075 /* Gopenpgpwrapper.framework in Frameworks */, DCC408C71E307DBB00F29B0E /* SVProgressHUD.framework in Frameworks */, 18F19A67B0C07F13C17169E0 /* Pods_pass.framework in Frameworks */, ); @@ -768,6 +772,7 @@ B975797E0F0B7476CADD6A7D /* Pods_passExtension.framework */, DAB3F5541E51ADC8C6B56642 /* Pods_passKit.framework */, CF843B3CF7D55A4070CBA1E4 /* Pods_passKitTests.framework */, + 1154BEDB229AC00F00454075 /* Gopenpgpwrapper.framework */, ); name = Frameworks; sourceTree = ""; @@ -830,7 +835,6 @@ A260757C1EEC6F34005DB03E /* Sources */, A260757D1EEC6F34005DB03E /* Frameworks */, A260757E1EEC6F34005DB03E /* Resources */, - 6AEAED0AF4328940B21EAC44 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -890,7 +894,6 @@ DC917BEC1E2F3659000FDF54 /* Run Script */, A26700191EEC450100176B8A /* Embed App Extensions */, A26075921EEC6F34005DB03E /* Embed Frameworks */, - 7F5ED3FD24ED627DC957D425 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -1093,26 +1096,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 6AEAED0AF4328940B21EAC44 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-passKitTests/Pods-passKitTests-frameworks.sh", - "${PODS_ROOT}/ObjectivePGP/Frameworks/ios/ObjectivePGP.framework", - "${PODS_ROOT}/ObjectivePGP/Frameworks/ios/ObjectivePGP.framework.dSYM", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ObjectivePGP.framework", - "${DWARF_DSYM_FOLDER_PATH}/ObjectivePGP.framework.dSYM", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-passKitTests/Pods-passKitTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 736C6F64F90A20CB9A00B420 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1131,26 +1114,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 7F5ED3FD24ED627DC957D425 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-pass/Pods-pass-frameworks.sh", - "${PODS_ROOT}/ObjectivePGP/Frameworks/ios/ObjectivePGP.framework", - "${PODS_ROOT}/ObjectivePGP/Frameworks/ios/ObjectivePGP.framework.dSYM", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ObjectivePGP.framework", - "${DWARF_DSYM_FOLDER_PATH}/ObjectivePGP.framework.dSYM", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-pass/Pods-pass-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 94AA4FCF7FF3474A970BE194 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1502,7 +1465,10 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/go/dist", + ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1541,7 +1507,10 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/go/dist", + ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = passKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1830,7 +1799,10 @@ DEFINES_MODULE = NO; DEVELOPMENT_TEAM = 4WDM8E95VU; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/go/dist", + ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = pass/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -1862,7 +1834,10 @@ DEFINES_MODULE = NO; DEVELOPMENT_TEAM = 4WDM8E95VU; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/go/dist", + ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = pass/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; diff --git a/pass/Controllers/SettingsTableViewController.swift b/pass/Controllers/SettingsTableViewController.swift index a18b81c..a5dca05 100644 --- a/pass/Controllers/SettingsTableViewController.swift +++ b/pass/Controllers/SettingsTableViewController.swift @@ -38,8 +38,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele SVProgressHUD.show(withStatus: "FetchingPgpKey".localize()) DispatchQueue.global(qos: .userInitiated).async { [unowned self] in do { - try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPublicKeyURL]!, keyType: .public) - try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPrivateKeyURL]!, keyType: .secret) + try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPublicKeyURL]!, keyType: .PUBLIC) + try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPrivateKeyURL]!, keyType: .PRIVATE) DispatchQueue.main.async { self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID SVProgressHUD.showSuccess(withStatus: "Success".localize()) @@ -68,8 +68,8 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele SVProgressHUD.show(withStatus: "FetchingPgpKey".localize()) DispatchQueue.global(qos: .userInitiated).async { [unowned self] in do { - try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPublicKeyArmor] ?? "", keyType: .public) - try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPrivateKeyArmor] ?? "", keyType: .secret) + try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPublicKeyArmor] ?? "", keyType: .PUBLIC) + try self.passwordStore.initPGPKey(with: SharedDefaults[.pgpPrivateKeyArmor] ?? "", keyType: .PRIVATE) DispatchQueue.main.async { self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID SVProgressHUD.showSuccess(withStatus: "Success".localize()) diff --git a/pass/Helpers/Objective-CBridgingHeader.h b/pass/Helpers/Objective-CBridgingHeader.h index 5a04d04..0c6b9fa 100644 --- a/pass/Helpers/Objective-CBridgingHeader.h +++ b/pass/Helpers/Objective-CBridgingHeader.h @@ -9,7 +9,6 @@ #ifndef Objective_CBridgingHeader_h #define Objective_CBridgingHeader_h -#import "ObjectivePGP/ObjectivePGP.h" #import "ObjectiveGit/ObjectiveGit.h" #endif /* Objective_CBridgingHeader_h */ diff --git a/passKit/Models/PasswordStore.swift b/passKit/Models/PasswordStore.swift index 21685d9..8923042 100644 --- a/passKit/Models/PasswordStore.swift +++ b/passKit/Models/PasswordStore.swift @@ -11,8 +11,8 @@ import CoreData import UIKit import SwiftyUserDefaults import ObjectiveGit -import ObjectivePGP import KeychainAccess +import Gopenpgpwrapper public class PasswordStore { public static let shared = PasswordStore() @@ -22,19 +22,26 @@ public class PasswordStore { dateFormatter.timeStyle = .short return dateFormatter }() - + public let storeURL = URL(fileURLWithPath: "\(Globals.repositoryPath)") public let tempStoreURL = URL(fileURLWithPath: "\(Globals.repositoryPath)-temp") - + public var storeRepository: GTRepository? public var pgpKeyID: String? - public var publicKey: Key? { + public var publicKey: GopenpgpwrapperKey? { didSet { - pgpKeyID = publicKey?.keyID.shortIdentifier + if publicKey != nil { + pgpKeyID = publicKey!.getID() + } else { + pgpKeyID = nil + } } } - public var privateKey: Key? - + public var privateKey: GopenpgpwrapperKey? + public enum PGPKeyType { + case PUBLIC, PRIVATE + } + public var gitSignatureForNow: GTSignature { get { let gitSignatureName = SharedDefaults[.gitSignatureName] ?? Globals.gitSignatureDefaultName @@ -42,9 +49,7 @@ public class PasswordStore { return GTSignature(name: gitSignatureName, email: gitSignatureEmail, time: Date())! } } - - public let keyring = ObjectivePGP.defaultKeyring - + public var pgpKeyPassphrase: String? { set { Utils.addPasswordToKeychain(name: "pgpKeyPassphrase", password: newValue) @@ -53,7 +58,7 @@ public class PasswordStore { return Utils.getPasswordFromKeychain(name: "pgpKeyPassphrase") } } - + public var gitPassword: String? { set { Utils.addPasswordToKeychain(name: "gitPassword", password: newValue) @@ -62,7 +67,7 @@ public class PasswordStore { return Utils.getPasswordFromKeychain(name: "gitPassword") } } - + public var gitSSHPrivateKeyPassphrase: String? { set { Utils.addPasswordToKeychain(name: "gitSSHPrivateKeyPassphrase", password: newValue) @@ -71,7 +76,7 @@ public class PasswordStore { return Utils.getPasswordFromKeychain(name: "gitSSHPrivateKeyPassphrase") } } - + private let fm = FileManager.default lazy private var context: NSManagedObjectContext = { let modelURL = Bundle(identifier: Globals.passKitBundleIdentifier)!.url(forResource: "pass", withExtension: "momd")! @@ -85,7 +90,7 @@ public class PasswordStore { if let error = error as NSError? { // Replace this implementation with code to handle the error appropriately. // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. - + /* Typical reasons for an error here include: * The parent directory does not exist, cannot be created, or disallows writing. @@ -99,28 +104,32 @@ public class PasswordStore { }) return container.viewContext }() - + public var numberOfPasswords : Int { return self.fetchPasswordEntityCoreData(withDir: false).count } - + public var sizeOfRepositoryByteCount : UInt64 { return (try? fm.allocatedSizeOfDirectoryAtURL(directoryURL: self.storeURL)) ?? 0 } - + public var numberOfLocalCommits: Int? { - return (try? getLocalCommits())?.count + return (try? getLocalCommits())?.flatMap { $0.count } } - + public var lastSyncedTime: Date? { return SharedDefaults[.lastSyncedTime] } - + public var numberOfCommits: UInt? { return storeRepository?.numberOfCommits(inCurrentBranch: nil) } - + private init() { + // File migration to group + migrateIfNeeded() + backwardCompatibility() + do { if fm.fileExists(atPath: storeURL.path) { try storeRepository = GTRepository.init(url: storeURL) @@ -130,30 +139,76 @@ public class PasswordStore { print(error) } } - + + private func migrateIfNeeded() { + // migrate happens only if the repository was cloned and pgp keys were set up using earlier versions + let needMigration = !pgpKeyExists() && !gitSSHKeyExists() && !fm.fileExists(atPath: Globals.repositoryPath) && fm.fileExists(atPath: Globals.repositoryPathLegacy) + guard needMigration == true else { + return + } + + do { + // migrate Defaults + let userDefaults = UserDefaults() + for key in Defaults.dictionaryRepresentation().keys { + if SharedDefaults.value(forKey: key) == nil { + SharedDefaults.setValue(userDefaults.value(forKey: key), forKey: key) + } + } + + // migrate files + try fm.createDirectory(atPath: Globals.documentPath, withIntermediateDirectories: true, attributes: nil) + try fm.createDirectory(atPath: Globals.libraryPath, withIntermediateDirectories: true, attributes: nil) + if fm.fileExists(atPath: Globals.pgpPublicKeyPathLegacy) { + try fm.moveItem(atPath: Globals.pgpPublicKeyPathLegacy, toPath: Globals.pgpPublicKeyPath) + } + if fm.fileExists(atPath: Globals.pgpPrivateKeyPathLegacy) { + try fm.moveItem(atPath: Globals.pgpPrivateKeyPathLegacy, toPath: Globals.pgpPrivateKeyPath) + } + if fm.fileExists(atPath: Globals.gitSSHPrivateKeyPathLegacy) { + try fm.moveItem(atPath: Globals.gitSSHPrivateKeyPathLegacy, toPath: Globals.gitSSHPrivateKeyPath) + } + try fm.moveItem(atPath: Globals.repositoryPathLegacy, toPath: Globals.repositoryPath) + } catch { + print("MigrationError".localize(error)) + } + updatePasswordEntityCoreData() + } + + private func backwardCompatibility() { + // For the newly-introduced isRememberGitCredentialPassphraseOn (20171008) + if (self.gitPassword != nil || self.gitSSHPrivateKeyPassphrase != nil) && SharedDefaults[.isRememberGitCredentialPassphraseOn] == false { + SharedDefaults[.isRememberGitCredentialPassphraseOn] = true + } + // For the renamed isRememberPGPPassphraseOn (20171008) + if self.pgpKeyPassphrase != nil && SharedDefaults[.isRememberPGPPassphraseOn] == false { + SharedDefaults[.isRememberPGPPassphraseOn] = true + } + } + enum SSHKeyType { case `public`, secret } - + public func initGitSSHKey(with armorKey: String) throws { let keyPath = Globals.gitSSHPrivateKeyPath try armorKey.write(toFile: keyPath, atomically: true, encoding: .ascii) } - + public func initPGPKeys() throws { - try initPGPKey(.public) - try initPGPKey(.secret) + try initPGPKey(.PUBLIC) + try initPGPKey(.PRIVATE) } - + public func initPGPKey(_ keyType: PGPKeyType) throws { switch keyType { - case .public: + case .PUBLIC: let keyPath = Globals.pgpPublicKeyPath self.publicKey = importKey(from: keyPath) if self.publicKey == nil { throw AppError.KeyImport } - case .secret: + case .PRIVATE: let keyPath = Globals.pgpPrivateKeyPath self.privateKey = importKey(from: keyPath) if self.privateKey == nil { @@ -163,10 +218,10 @@ public class PasswordStore { throw AppError.Unknown } } - + public func initPGPKey(from url: URL, keyType: PGPKeyType) throws { var pgpKeyLocalPath = "" - if keyType == .public { + if keyType == .PUBLIC { pgpKeyLocalPath = Globals.pgpPublicKeyPath } else { pgpKeyLocalPath = Globals.pgpPrivateKeyPath @@ -175,10 +230,10 @@ public class PasswordStore { try pgpKeyData.write(to: URL(fileURLWithPath: pgpKeyLocalPath), options: .atomic) try initPGPKey(keyType) } - + public func initPGPKey(with armorKey: String, keyType: PGPKeyType) throws { var pgpKeyLocalPath = "" - if keyType == .public { + if keyType == .PUBLIC { pgpKeyLocalPath = Globals.pgpPublicKeyPath } else { pgpKeyLocalPath = Globals.pgpPrivateKeyPath @@ -186,28 +241,21 @@ public class PasswordStore { try armorKey.write(toFile: pgpKeyLocalPath, atomically: true, encoding: .ascii) try initPGPKey(keyType) } - - - private func importKey(from keyPath: String) -> Key? { + + + private func importKey(from keyPath: String) -> GopenpgpwrapperKey? { if fm.fileExists(atPath: keyPath) { - let keys = try! ObjectivePGP.readKeys(fromPath: keyPath) - keyring.import(keys: keys) - if !keys.isEmpty { - return keys.first - } + return GopenpgpwrapperReadKey(fm.contents(atPath: keyPath)) } return nil } - - public func getPgpPrivateKey() -> Key { - return keyring.keys.filter({$0.secretKey != nil})[0] - } - + + public func repositoryExisted() -> Bool { let fm = FileManager() return fm.fileExists(atPath: Globals.repositoryPath) } - + public func passwordExisted(password: Password) -> Bool { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") do { @@ -221,8 +269,9 @@ public class PasswordStore { } catch { fatalError("FailedToFetchPasswordEntities".localize(error)) } + return true } - + public func passwordEntityExisted(path: String) -> Bool { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") do { @@ -236,8 +285,9 @@ public class PasswordStore { } catch { fatalError("FailedToFetchPasswordEntities".localize(error)) } + return true } - + public func getPasswordEntity(by path: String, isDir: Bool) -> PasswordEntity? { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") do { @@ -247,13 +297,13 @@ public class PasswordStore { fatalError("FailedToFetchPasswordEntities".localize(error)) } } - + public func cloneRepository(remoteRepoURL: URL, - credential: GitCredential, - branchName: String, - requestGitPassword: @escaping (GitCredential.Credential, String?) -> String?, - transferProgressBlock: @escaping (UnsafePointer, UnsafeMutablePointer) -> Void, - checkoutProgressBlock: @escaping (String?, UInt, UInt) -> Void) throws { + credential: GitCredential, + branchName: String, + requestGitPassword: @escaping (GitCredential.Credential, String?) -> String?, + transferProgressBlock: @escaping (UnsafePointer, UnsafeMutablePointer) -> Void, + checkoutProgressBlock: @escaping (String?, UInt, UInt) -> Void) throws { try? fm.removeItem(at: storeURL) try? fm.removeItem(at: tempStoreURL) self.gitPassword = nil @@ -280,7 +330,7 @@ public class PasswordStore { NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) } } - + private func checkoutAndChangeBranch(withName localBranchName: String) throws { if (localBranchName == "master") { return @@ -301,7 +351,7 @@ public class PasswordStore { try storeRepository.checkoutReference(localBranch.reference, options: checkoutOptions) try storeRepository.moveHEAD(to: localBranch.reference) } - + public func pullRepository(credential: GitCredential, requestGitPassword: @escaping (GitCredential.Credential, String?) -> String?, transferProgressBlock: @escaping (UnsafePointer, UnsafeMutablePointer) -> Void) throws { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSet @@ -317,22 +367,22 @@ public class PasswordStore { NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) } } - + private func updatePasswordEntityCoreData() { deleteCoreData(entityName: "PasswordEntity") do { var q = try fm.contentsOfDirectory(atPath: self.storeURL.path).filter{ !$0.hasPrefix(".") - }.map { (filename) -> PasswordEntity in - let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity - if filename.hasSuffix(".gpg") { - passwordEntity.name = String(filename.prefix(upTo: filename.index(filename.endIndex, offsetBy: -4))) - } else { - passwordEntity.name = filename - } - passwordEntity.path = filename - passwordEntity.parent = nil - return passwordEntity + }.map { (filename) -> PasswordEntity in + let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: context) as! PasswordEntity + if filename.hasSuffix(".gpg") { + passwordEntity.name = String(filename.prefix(upTo: filename.index(filename.endIndex, offsetBy: -4))) + } else { + passwordEntity.name = filename + } + passwordEntity.path = filename + passwordEntity.parent = nil + return passwordEntity } while q.count > 0 { let e = q.first! @@ -371,7 +421,7 @@ public class PasswordStore { print("ErrorSaving".localize(error)) } } - + public func getRecentCommits(count: Int) throws -> [GTCommit] { guard let storeRepository = storeRepository else { return [] @@ -388,7 +438,7 @@ public class PasswordStore { } return commits } - + public func fetchPasswordEntityCoreData(parent: PasswordEntity?) -> [PasswordEntity] { let passwordEntityFetch = NSFetchRequest(entityName: "PasswordEntity") do { @@ -399,7 +449,7 @@ public class PasswordStore { fatalError("FailedToFetchPasswords".localize(error)) } } - + public func fetchPasswordEntityCoreData(withDir: Bool) -> [PasswordEntity] { let passwordEntityFetch = NSFetchRequest(entityName: "PasswordEntity") do { @@ -412,8 +462,8 @@ public class PasswordStore { fatalError("FailedToFetchPasswords".localize(error)) } } - - + + public func fetchUnsyncedPasswords() -> [PasswordEntity] { let passwordEntityFetchRequest = NSFetchRequest(entityName: "PasswordEntity") passwordEntityFetchRequest.predicate = NSPredicate(format: "synced = %i", 0) @@ -424,7 +474,7 @@ public class PasswordStore { fatalError("FailedToFetchPasswords".localize(error)) } } - + public func setAllSynced() { let passwordEntities = fetchUnsyncedPasswords() for passwordEntity in passwordEntities { @@ -438,16 +488,16 @@ public class PasswordStore { fatalError("ErrorSaving".localize(error)) } } - + public func getLatestUpdateInfo(filename: String) -> String { guard let storeRepository = storeRepository else { return "Unknown".localize() } guard let blameHunks = try? storeRepository.blame(withFile: filename, options: nil).hunks, let latestCommitTime = blameHunks.map({ - $0.finalSignature?.time?.timeIntervalSince1970 ?? 0 + $0.finalSignature?.time?.timeIntervalSince1970 ?? 0 }).max() else { - return "Unknown".localize() + return "Unknown".localize() } let lastCommitDate = Date(timeIntervalSince1970: latestCommitTime) if Date().timeIntervalSince(lastCommitDate) <= 60 { @@ -455,10 +505,10 @@ public class PasswordStore { } return PasswordStore.dateFormatter.string(from: lastCommitDate) } - + public func updateRemoteRepo() { } - + private func gitAdd(path: String) throws { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSet @@ -466,7 +516,7 @@ public class PasswordStore { try storeRepository.index().addFile(path) try storeRepository.index().write() } - + private func gitRm(path: String) throws { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSet @@ -478,7 +528,7 @@ public class PasswordStore { try storeRepository.index().removeFile(path) try storeRepository.index().write() } - + private func deleteDirectoryTree(at url: URL) throws { var tempURL = storeURL.appendingPathComponent(url.deletingLastPathComponent().path) var count = try fm.contentsOfDirectory(atPath: tempURL.path).count @@ -488,12 +538,12 @@ public class PasswordStore { count = try fm.contentsOfDirectory(atPath: tempURL.path).count } } - + private func createDirectoryTree(at url: URL) throws { let tempURL = storeURL.appendingPathComponent(url.deletingLastPathComponent().path) try fm.createDirectory(at: tempURL, withIntermediateDirectories: true, attributes: nil) } - + private func gitMv(from: String, to: String) throws { let fromURL = storeURL.appendingPathComponent(from) let toURL = storeURL.appendingPathComponent(to) @@ -501,7 +551,7 @@ public class PasswordStore { try gitAdd(path: to) try gitRm(path: from) } - + private func gitCommit(message: String) throws -> GTCommit? { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSet @@ -515,7 +565,7 @@ public class PasswordStore { let commit = try storeRepository.createCommit(with: newTree, message: message, author: signature, committer: signature, parents: [parent], updatingReferenceNamed: headReference.name) return commit } - + private func getLocalBranch(withName branchName: String) throws -> GTBranch? { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSet @@ -524,7 +574,7 @@ public class PasswordStore { let branches = try storeRepository.branches(withPrefix: reference) return branches.first } - + public func pushRepository(credential: GitCredential, requestGitPassword: @escaping (GitCredential.Credential, String?) -> String?, transferProgressBlock: @escaping (UInt32, UInt32, Int, UnsafeMutablePointer) -> Void) throws { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSet @@ -540,12 +590,12 @@ public class PasswordStore { throw(error) } } - + private func addPasswordEntities(password: Password) throws -> PasswordEntity? { guard !passwordExisted(password: password) else { throw AppError.PasswordDuplicated } - + var passwordURL = password.url var previousPathLength = Int.max var paths: [String] = [] @@ -575,7 +625,7 @@ public class PasswordStore { } return nil } - + private func insertPasswordEntity(name: String, path: String, parent: PasswordEntity?, synced: Bool = false, isDir: Bool = false) -> PasswordEntity? { var ret: PasswordEntity? = nil if let passwordEntity = NSEntityDescription.insertNewObject(forEntityName: "PasswordEntity", into: self.context) as? PasswordEntity { @@ -593,7 +643,7 @@ public class PasswordStore { } return ret } - + public func add(password: Password) throws -> PasswordEntity? { try createDirectoryTree(at: password.url) let newPasswordEntity = try addPasswordEntities(password: password) @@ -604,7 +654,7 @@ public class PasswordStore { NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) return newPasswordEntity } - + public func delete(passwordEntity: PasswordEntity) throws { let deletedFileURL = passwordEntity.getURL()! try gitRm(path: deletedFileURL.path) @@ -613,10 +663,10 @@ public class PasswordStore { let _ = try gitCommit(message: "RemovePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!)) NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) } - + public func edit(passwordEntity: PasswordEntity, password: Password) throws -> PasswordEntity? { var newPasswordEntity: PasswordEntity? = passwordEntity - + if password.changed&PasswordChange.content.rawValue != 0 { let saveURL = storeURL.appendingPathComponent(passwordEntity.getURL()!.path) try self.encrypt(password: password).write(to: saveURL) @@ -625,27 +675,25 @@ public class PasswordStore { newPasswordEntity = passwordEntity newPasswordEntity?.synced = false } - + if password.changed&PasswordChange.path.rawValue != 0 { let deletedFileURL = passwordEntity.getURL()! // add try createDirectoryTree(at: password.url) newPasswordEntity = try addPasswordEntities(password: password) - + // mv try gitMv(from: deletedFileURL.path, to: password.url.path) - + // delete try deleteDirectoryTree(at: deletedFileURL) try deletePasswordEntities(passwordEntity: passwordEntity) let _ = try gitCommit(message: "RenamePassword.".localize(deletedFileURL.deletingPathExtension().path.removingPercentEncoding!, password.url.deletingPathExtension().path.removingPercentEncoding!)) } - - self.saveUpdated(passwordEntity: newPasswordEntity!) NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) return newPasswordEntity } - + private func deletePasswordEntities(passwordEntity: PasswordEntity) throws { var current: PasswordEntity? = passwordEntity while current != nil && (current!.children!.count == 0 || !current!.isDir) { @@ -659,7 +707,7 @@ public class PasswordStore { } } } - + public func saveUpdated(passwordEntity: PasswordEntity) { do { try context.save() @@ -667,11 +715,11 @@ public class PasswordStore { fatalError("FailedToSavePasswordEntity".localize(error)) } } - + public func deleteCoreData(entityName: String) { let deleteFetchRequest = NSFetchRequest(entityName: entityName) let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetchRequest) - + do { try context.execute(deleteRequest) try context.save() @@ -680,7 +728,7 @@ public class PasswordStore { print(error) } } - + public func updateImage(passwordEntity: PasswordEntity, image: Data?) { guard let image = image else { return @@ -703,28 +751,28 @@ public class PasswordStore { } } } - + public func erase() { publicKey = nil privateKey = nil try? fm.removeItem(at: storeURL) try? fm.removeItem(at: tempStoreURL) - + try? fm.removeItem(atPath: Globals.pgpPublicKeyPath) try? fm.removeItem(atPath: Globals.pgpPrivateKeyPath) try? fm.removeItem(atPath: Globals.gitSSHPrivateKeyPath) - + Utils.removeAllKeychain() - + deleteCoreData(entityName: "PasswordEntity") - + SharedDefaults.removeAll() storeRepository = nil - + NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) NotificationCenter.default.post(name: .passwordStoreErased, object: nil) } - + // return the number of discarded commits public func reset() throws -> Int { guard let storeRepository = storeRepository else { @@ -742,7 +790,7 @@ public class PasswordStore { try storeRepository.reset(to: newHead, resetType: .hard) self.setAllSynced() self.updatePasswordEntityCoreData() - + NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) NotificationCenter.default.post(name: .passwordStoreChangeDiscarded, object: nil) return localCommits.count @@ -750,8 +798,8 @@ public class PasswordStore { return 0 // no new commit } } - - + + private func getLocalCommits() throws -> [GTCommit]? { guard let storeRepository = storeRepository else { throw AppError.RepositoryNotSet @@ -765,13 +813,13 @@ public class PasswordStore { guard remoteBranch.oid != nil else { throw AppError.RepositoryRemoteBranchNotFound(remoteBranchName) } - + // get a list of local commits return try storeRepository.localCommitsRelative(toRemoteBranch: remoteBranch) } - - - + + + public func decrypt(passwordEntity: PasswordEntity, requestPGPKeyPassphrase: () -> String) throws -> Password? { let encryptedDataPath = storeURL.appendingPathComponent(passwordEntity.getPath()) let encryptedData = try Data(contentsOf: encryptedDataPath) @@ -779,27 +827,24 @@ public class PasswordStore { if passphrase == nil { passphrase = requestPGPKeyPassphrase() } - let decryptedData = try ObjectivePGP.decrypt(encryptedData, andVerifySignature: false, using: keyring.keys, passphraseForKey: {(_) in passphrase}) - let plainText = String(data: decryptedData, encoding: .utf8) ?? "" + let decryptedData = privateKey?.decrypt(encryptedData, passphrase: passphrase) + let plainText = String(data: decryptedData!, encoding: .utf8) ?? "" guard let url = passwordEntity.getURL() else { throw AppError.Decryption } return Password(name: passwordEntity.getName(), url: url, plainText: plainText) } - + public func encrypt(password: Password) throws -> Data { - guard keyring.keys.count > 0 else { + guard publicKey != nil else { throw AppError.PgpPublicKeyNotExist } let plainData = password.plainData - let encryptedData = try ObjectivePGP.encrypt(plainData, addSignature: false, using: keyring.keys, passphraseForKey: nil) - if SharedDefaults[.encryptInArmored] { - return Armor.armored(encryptedData, as: .message).data(using: .utf8)! - } else { - return encryptedData - } + let encryptedData = publicKey?.encrypt(plainData, armor: SharedDefaults[.encryptInArmored]) + + return encryptedData! } - + public func removePGPKeys() { try? fm.removeItem(atPath: Globals.pgpPublicKeyPath) try? fm.removeItem(atPath: Globals.pgpPrivateKeyPath) @@ -809,18 +854,17 @@ public class PasswordStore { SharedDefaults.remove(.pgpPrivateKeyURL) SharedDefaults.remove(.pgpPublicKeyURL) Utils.removeKeychain(name: ".pgpKeyPassphrase") - keyring.deleteAll() publicKey = nil privateKey = nil } - + public func removeGitSSHKeys() { try? fm.removeItem(atPath: Globals.gitSSHPrivateKeyPath) Defaults.remove(.gitSSHPrivateKeyArmor) Defaults.remove(.gitSSHPrivateKeyURL) self.gitSSHPrivateKeyPassphrase = nil } - + public func gitSSHKeyExists(inFileSharing: Bool = false) -> Bool { if inFileSharing == false { return fm.fileExists(atPath: Globals.gitSSHPrivateKeyPath) @@ -828,7 +872,7 @@ public class PasswordStore { return fm.fileExists(atPath: Globals.iTunesFileSharingSSHPrivate) } } - + public func pgpKeyExists(inFileSharing: Bool = false) -> Bool { if inFileSharing == false { return fm.fileExists(atPath: Globals.pgpPublicKeyPath) && fm.fileExists(atPath: Globals.pgpPrivateKeyPath) @@ -836,19 +880,12 @@ public class PasswordStore { return fm.fileExists(atPath: Globals.iTunesFileSharingPGPPublic) && fm.fileExists(atPath: Globals.iTunesFileSharingPGPPrivate) } } - + public func gitSSHKeyImportFromFileSharing() throws { - if gitSSHKeyExists() { - try fm.removeItem(atPath: Globals.gitSSHPrivateKeyPath) - } try fm.moveItem(atPath: Globals.iTunesFileSharingSSHPrivate, toPath: Globals.gitSSHPrivateKeyPath) } - + public func pgpKeyImportFromFileSharing() throws { - if pgpKeyExists() { - try fm.removeItem(atPath: Globals.pgpPublicKeyPath) - try fm.removeItem(atPath: Globals.pgpPrivateKeyPath) - } try fm.moveItem(atPath: Globals.iTunesFileSharingPGPPublic, toPath: Globals.pgpPublicKeyPath) try fm.moveItem(atPath: Globals.iTunesFileSharingPGPPrivate, toPath: Globals.pgpPrivateKeyPath) }