compatibilty for plugins is now fetched from plugin repository

This commit is contained in:
Michael Starke
2018-10-10 19:23:45 +02:00
parent 74b06ed195
commit 0921cd39d2
19 changed files with 559 additions and 66 deletions

View File

@@ -148,6 +148,8 @@
4C6F228C19A4AA700012310C /* MPAutotypeDelay.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6F228B19A4AA700012310C /* MPAutotypeDelay.m */; }; 4C6F228C19A4AA700012310C /* MPAutotypeDelay.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6F228B19A4AA700012310C /* MPAutotypeDelay.m */; };
4C701CBC178618A000581B88 /* 12_RemoteTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C701CBB178618A000581B88 /* 12_RemoteTemplate.pdf */; }; 4C701CBC178618A000581B88 /* 12_RemoteTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C701CBB178618A000581B88 /* 12_RemoteTemplate.pdf */; };
4C7155D81A10DB6D00979307 /* IconSelection.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C7155DA1A10DB6D00979307 /* IconSelection.xib */; }; 4C7155D81A10DB6D00979307 /* IconSelection.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C7155DA1A10DB6D00979307 /* IconSelection.xib */; };
4C71BCB42167B75900B4CBDA /* MPTestPluginVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C71BCB32167B75900B4CBDA /* MPTestPluginVersion.m */; };
4C71BCB72167B79C00B4CBDA /* MPPluginVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C71BCB62167B79C00B4CBDA /* MPPluginVersion.m */; };
4C735FC02035FCBF00708D53 /* MPPluginEntryActionContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C735FBF2035FCBF00708D53 /* MPPluginEntryActionContext.m */; }; 4C735FC02035FCBF00708D53 /* MPPluginEntryActionContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C735FBF2035FCBF00708D53 /* MPPluginEntryActionContext.m */; };
4C73B6F1215E64A7009787F7 /* MPWelcomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C73B6EF215E64A7009787F7 /* MPWelcomeViewController.m */; }; 4C73B6F1215E64A7009787F7 /* MPWelcomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C73B6EF215E64A7009787F7 /* MPWelcomeViewController.m */; };
4C76155C1764C04C0015A1A6 /* GeneralSettings.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C76155E1764C04C0015A1A6 /* GeneralSettings.xib */; }; 4C76155C1764C04C0015A1A6 /* GeneralSettings.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C76155E1764C04C0015A1A6 /* GeneralSettings.xib */; };
@@ -183,6 +185,7 @@
4C7BD07619FE94C900C7AA5C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4C7BD07519FE94C900C7AA5C /* Assets.xcassets */; }; 4C7BD07619FE94C900C7AA5C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4C7BD07519FE94C900C7AA5C /* Assets.xcassets */; };
4C7F8B681A10B68400CCB83D /* WelcomeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C7F8B6A1A10B68400CCB83D /* WelcomeView.xib */; }; 4C7F8B681A10B68400CCB83D /* WelcomeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C7F8B6A1A10B68400CCB83D /* WelcomeView.xib */; };
4C80304A1E2FBAA300133E4C /* MPTestKeyMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8030491E2FBAA300133E4C /* MPTestKeyMapper.m */; }; 4C80304A1E2FBAA300133E4C /* MPTestKeyMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8030491E2FBAA300133E4C /* MPTestKeyMapper.m */; };
4C81867D216664C70068DAFB /* MPPluginRepositoryItemVersionInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C81867C216664C70068DAFB /* MPPluginRepositoryItemVersionInfo.m */; };
4C82046A1FCDC07800EB24A4 /* MPPickfieldViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8204681FCDC07800EB24A4 /* MPPickfieldViewController.m */; }; 4C82046A1FCDC07800EB24A4 /* MPPickfieldViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8204681FCDC07800EB24A4 /* MPPickfieldViewController.m */; };
4C82046E1FCDC8A100EB24A4 /* MPPickfieldTableModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C82046D1FCDC8A100EB24A4 /* MPPickfieldTableModel.m */; }; 4C82046E1FCDC8A100EB24A4 /* MPPickfieldTableModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C82046D1FCDC8A100EB24A4 /* MPPickfieldTableModel.m */; };
4C83814215BF4677001AE468 /* MPDocumentWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C83814115BF4677001AE468 /* MPDocumentWindowController.m */; }; 4C83814215BF4677001AE468 /* MPDocumentWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C83814115BF4677001AE468 /* MPDocumentWindowController.m */; };
@@ -573,6 +576,9 @@
4C7155E81A10DB7700979307 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/IconSelection.strings; sourceTree = "<group>"; }; 4C7155E81A10DB7700979307 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/IconSelection.strings; sourceTree = "<group>"; };
4C7155EA1A10DB7800979307 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/IconSelection.strings; sourceTree = "<group>"; }; 4C7155EA1A10DB7800979307 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/IconSelection.strings; sourceTree = "<group>"; };
4C7155EC1A10DB7900979307 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/IconSelection.strings; sourceTree = "<group>"; }; 4C7155EC1A10DB7900979307 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/IconSelection.strings; sourceTree = "<group>"; };
4C71BCB32167B75900B4CBDA /* MPTestPluginVersion.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPTestPluginVersion.m; sourceTree = "<group>"; };
4C71BCB52167B79C00B4CBDA /* MPPluginVersion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPluginVersion.h; sourceTree = "<group>"; };
4C71BCB62167B79C00B4CBDA /* MPPluginVersion.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPluginVersion.m; sourceTree = "<group>"; };
4C735FBE2035FCBF00708D53 /* MPPluginEntryActionContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPluginEntryActionContext.h; sourceTree = "<group>"; }; 4C735FBE2035FCBF00708D53 /* MPPluginEntryActionContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPluginEntryActionContext.h; sourceTree = "<group>"; };
4C735FBF2035FCBF00708D53 /* MPPluginEntryActionContext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPluginEntryActionContext.m; sourceTree = "<group>"; }; 4C735FBF2035FCBF00708D53 /* MPPluginEntryActionContext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPluginEntryActionContext.m; sourceTree = "<group>"; };
4C73B6EE215E64A7009787F7 /* MPWelcomeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPWelcomeViewController.h; sourceTree = "<group>"; }; 4C73B6EE215E64A7009787F7 /* MPWelcomeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPWelcomeViewController.h; sourceTree = "<group>"; };
@@ -643,6 +649,8 @@
4C7F8B7A1A10B69700CCB83D /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/WelcomeView.strings; sourceTree = "<group>"; }; 4C7F8B7A1A10B69700CCB83D /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/WelcomeView.strings; sourceTree = "<group>"; };
4C7F8B7C1A10B69800CCB83D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/WelcomeView.strings; sourceTree = "<group>"; }; 4C7F8B7C1A10B69800CCB83D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/WelcomeView.strings; sourceTree = "<group>"; };
4C8030491E2FBAA300133E4C /* MPTestKeyMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTestKeyMapper.m; sourceTree = "<group>"; }; 4C8030491E2FBAA300133E4C /* MPTestKeyMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTestKeyMapper.m; sourceTree = "<group>"; };
4C81867B216664C70068DAFB /* MPPluginRepositoryItemVersionInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPluginRepositoryItemVersionInfo.h; sourceTree = "<group>"; };
4C81867C216664C70068DAFB /* MPPluginRepositoryItemVersionInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPluginRepositoryItemVersionInfo.m; sourceTree = "<group>"; };
4C8204671FCDC07800EB24A4 /* MPPickfieldViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPickfieldViewController.h; sourceTree = "<group>"; }; 4C8204671FCDC07800EB24A4 /* MPPickfieldViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPickfieldViewController.h; sourceTree = "<group>"; };
4C8204681FCDC07800EB24A4 /* MPPickfieldViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPickfieldViewController.m; sourceTree = "<group>"; }; 4C8204681FCDC07800EB24A4 /* MPPickfieldViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPickfieldViewController.m; sourceTree = "<group>"; };
4C82046C1FCDC8A100EB24A4 /* MPPickfieldTableModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPickfieldTableModel.h; sourceTree = "<group>"; }; 4C82046C1FCDC8A100EB24A4 /* MPPickfieldTableModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPickfieldTableModel.h; sourceTree = "<group>"; };
@@ -1194,6 +1202,7 @@
4C6BC65F1A36717E00BDDF3D /* MPDatabaseSearch.m */, 4C6BC65F1A36717E00BDDF3D /* MPDatabaseSearch.m */,
4C8030491E2FBAA300133E4C /* MPTestKeyMapper.m */, 4C8030491E2FBAA300133E4C /* MPTestKeyMapper.m */,
4C8F0C721FCF1B7A00BE157F /* MPTestPickcharsParser.m */, 4C8F0C721FCF1B7A00BE157F /* MPTestPickcharsParser.m */,
4C71BCB32167B75900B4CBDA /* MPTestPluginVersion.m */,
4C45FB1F178E09ED0010007D /* Supporting Files */, 4C45FB1F178E09ED0010007D /* Supporting Files */,
); );
path = MacPassTests; path = MacPassTests;
@@ -1663,8 +1672,12 @@
4CA78BFF1FD58C92003C8560 /* MPPluginRepository.m */, 4CA78BFF1FD58C92003C8560 /* MPPluginRepository.m */,
4CAD338D205169D30068587E /* MPPluginRepositoryItem.h */, 4CAD338D205169D30068587E /* MPPluginRepositoryItem.h */,
4CAD338E205169D30068587E /* MPPluginRepositoryItem.m */, 4CAD338E205169D30068587E /* MPPluginRepositoryItem.m */,
4C81867B216664C70068DAFB /* MPPluginRepositoryItemVersionInfo.h */,
4C81867C216664C70068DAFB /* MPPluginRepositoryItemVersionInfo.m */,
4C735FBE2035FCBF00708D53 /* MPPluginEntryActionContext.h */, 4C735FBE2035FCBF00708D53 /* MPPluginEntryActionContext.h */,
4C735FBF2035FCBF00708D53 /* MPPluginEntryActionContext.m */, 4C735FBF2035FCBF00708D53 /* MPPluginEntryActionContext.m */,
4C71BCB52167B79C00B4CBDA /* MPPluginVersion.h */,
4C71BCB62167B79C00B4CBDA /* MPPluginVersion.m */,
); );
name = Plugin; name = Plugin;
path = MacPass; path = MacPass;
@@ -1913,6 +1926,7 @@
files = ( files = (
4C45FB2D178E0BCB0010007D /* MPDatabaseLoading.m in Sources */, 4C45FB2D178E0BCB0010007D /* MPDatabaseLoading.m in Sources */,
4C8DEAA21C314D2C00D24C32 /* MPTestAutotypeDelay.m in Sources */, 4C8DEAA21C314D2C00D24C32 /* MPTestAutotypeDelay.m in Sources */,
4C71BCB42167B75900B4CBDA /* MPTestPluginVersion.m in Sources */,
4C8F0C731FCF1B7A00BE157F /* MPTestPickcharsParser.m in Sources */, 4C8F0C731FCF1B7A00BE157F /* MPTestPickcharsParser.m in Sources */,
4C45FB30178E0CE20010007D /* MPTestDocument.m in Sources */, 4C45FB30178E0CE20010007D /* MPTestDocument.m in Sources */,
4C6BC6601A36717E00BDDF3D /* MPDatabaseSearch.m in Sources */, 4C6BC6601A36717E00BDDF3D /* MPDatabaseSearch.m in Sources */,
@@ -1966,6 +1980,7 @@
4C888C9316EB6F5E003D34A1 /* MPToolbarItem.m in Sources */, 4C888C9316EB6F5E003D34A1 /* MPToolbarItem.m in Sources */,
4CA182741F963FF600DD4A4A /* MPTitlebarColorAccessoryViewController.m in Sources */, 4CA182741F963FF600DD4A4A /* MPTitlebarColorAccessoryViewController.m in Sources */,
4C888C9716EB754B003D34A1 /* MPActionHelper.m in Sources */, 4C888C9716EB754B003D34A1 /* MPActionHelper.m in Sources */,
4C81867D216664C70068DAFB /* MPPluginRepositoryItemVersionInfo.m in Sources */,
4CDA35751EBA0CF2003CD59F /* NSString+MPComposedCharacterAdditions.m in Sources */, 4CDA35751EBA0CF2003CD59F /* NSString+MPComposedCharacterAdditions.m in Sources */,
4CE39ABF16ECE34A000FE29D /* MPIconSelectViewController.m in Sources */, 4CE39ABF16ECE34A000FE29D /* MPIconSelectViewController.m in Sources */,
4CE39AC416ECE4F7000FE29D /* MPIconImageView.m in Sources */, 4CE39AC416ECE4F7000FE29D /* MPIconImageView.m in Sources */,
@@ -2034,6 +2049,7 @@
4C1FA07B18231900003A3F8C /* MPDocument+Autotype.m in Sources */, 4C1FA07B18231900003A3F8C /* MPDocument+Autotype.m in Sources */,
4C4B7EE917A45EC6000234C7 /* MPDatePickingViewController.m in Sources */, 4C4B7EE917A45EC6000234C7 /* MPDatePickingViewController.m in Sources */,
4C4B7EEE17A467E1000234C7 /* MPGroupInspectorViewController.m in Sources */, 4C4B7EEE17A467E1000234C7 /* MPGroupInspectorViewController.m in Sources */,
4C71BCB72167B79C00B4CBDA /* MPPluginVersion.m in Sources */,
4C7B63721C0CB51F00D7038C /* TTTCryptographyTransformers.m in Sources */, 4C7B63721C0CB51F00D7038C /* TTTCryptographyTransformers.m in Sources */,
4C4B7EF317A467FC000234C7 /* MPEntryInspectorViewController.m in Sources */, 4C4B7EF317A467FC000234C7 /* MPEntryInspectorViewController.m in Sources */,
4C1BDF2B1E4392640012A3F0 /* MPPluginDataViewController.m in Sources */, 4C1BDF2B1E4392640012A3F0 /* MPPluginDataViewController.m in Sources */,

View File

@@ -189,7 +189,7 @@ Gw
<constraint firstItem="6" firstAttribute="leading" secondItem="9" secondAttribute="leading" id="zeJ-6i-fY3"/> <constraint firstItem="6" firstAttribute="leading" secondItem="9" secondAttribute="leading" id="zeJ-6i-fY3"/>
</constraints> </constraints>
</view> </view>
<point key="canvasLocation" x="-226" y="45"/> <point key="canvasLocation" x="-312" y="-21"/>
</window> </window>
</objects> </objects>
<resources> <resources>

View File

@@ -183,7 +183,7 @@ NSString *const MPDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDi
[MPLockDaemon defaultDaemon]; [MPLockDaemon defaultDaemon];
[MPAutotypeDaemon defaultDaemon]; [MPAutotypeDaemon defaultDaemon];
/* Create Plugin Manager */ /* Create Plugin Manager */
[MPPluginHost sharedHost]; [MPPluginHost.sharedHost loadPlugins];
#if !defined(DEBUG) && !defined(NO_SPARKLE) #if !defined(DEBUG) && !defined(NO_SPARKLE)
/* Disable updates if in debug or nosparkle */ /* Disable updates if in debug or nosparkle */
[SUUpdater sharedUpdater]; [SUUpdater sharedUpdater];

View File

@@ -196,17 +196,6 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGrou
} }
- (BOOL)readFromURL:(NSURL *)url ofType:(NSString *)typeName error:(NSError **)outError { - (BOOL)readFromURL:(NSURL *)url ofType:(NSString *)typeName error:(NSError **)outError {
/* FIXME: Lockfile handling
self.lockFileURL = [url URLByAppendingPathExtension:@"lock"];
if([[NSFileManager defaultManager] fileExistsAtPath:[_lockFileURL path]]) {
self.readOnly = YES;
}
else {
[[NSFileManager defaultManager] createFileAtPath:[_lockFileURL path] contents:nil attributes:nil];
_didLockFile = YES;
self.readOnly = NO;
}
*/
/* /*
Delete our old Tree, and just grab the data Delete our old Tree, and just grab the data
*/ */
@@ -939,7 +928,7 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGrou
- (void)_cleanupLock { - (void)_cleanupLock {
if(_didLockFile) { if(_didLockFile) {
[[NSFileManager defaultManager] removeItemAtURL:_lockFileURL error:nil]; [NSFileManager.defaultManager removeItemAtURL:_lockFileURL error:nil];
_didLockFile = NO; _didLockFile = NO;
} }
} }
@@ -971,11 +960,11 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGrou
#pragma mark MPModelChangeObserving #pragma mark MPModelChangeObserving
- (void)willChangeModelProperty { - (void)willChangeModelProperty {
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentWillChangeModelPropertyNotification object:self]; [NSNotificationCenter.defaultCenter postNotificationName:MPDocumentWillChangeModelPropertyNotification object:self];
} }
- (void)didChangeModelProperty { - (void)didChangeModelProperty {
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeModelPropertyNotification object:self]; [NSNotificationCenter.defaultCenter postNotificationName:MPDocumentDidChangeModelPropertyNotification object:self];
} }
@end @end

View File

@@ -37,7 +37,7 @@
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[delegate methodSignatureForSelector:didRecoverSelector]]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[delegate methodSignatureForSelector:didRecoverSelector]];
__block void *contextInfoCopy = contextInfo; __block void *contextInfoCopy = contextInfo;
if(error.code == MPErrorNoPasswordOrKeyFile) { if(error.code == MPErrorNoPasswordOrKeyFile) {
if([delegate isKindOfClass:[MPDocument class]]) { if([delegate isKindOfClass:MPDocument.class]) {
MPDocument *document = delegate; MPDocument *document = delegate;
BOOL didRecover = NO; BOOL didRecover = NO;
if(recoveryOptionIndex == 0) { if(recoveryOptionIndex == 0) {
@@ -59,7 +59,6 @@
} }
} }
} }
} }
/* Given that an error alert has been presented applicaton-modally to the user, and the user has chosen one of the error's recovery options, attempt recovery from the error, and return YES if error recovery was completely successful, NO otherwise. The recovery option index is an index into the error's array of localized recovery options. /* Given that an error alert has been presented applicaton-modally to the user, and the user has chosen one of the error's recovery options, attempt recovery from the error, and return YES if error recovery was completely successful, NO otherwise. The recovery option index is an index into the error's array of localized recovery options.

View File

@@ -35,7 +35,8 @@ FOUNDATION_EXPORT NSString *const MPPluginUnkownVersion;
@property (copy, readonly) NSString *identifier; @property (copy, readonly) NSString *identifier;
@property (copy, readonly) NSString *name; @property (copy, readonly) NSString *name;
@property (copy, readonly) NSString *version; @property (nonatomic, copy, readonly, nullable) NSString *humanVersionString;
@property (nonatomic, copy, readonly) NSString *versionString;
@property (nonatomic, strong, readonly) NSBundle *bundle; @property (nonatomic, strong, readonly) NSBundle *bundle;
/** /**

View File

@@ -68,9 +68,13 @@ NSString *const MPPluginUnkownVersion = @"unkown.plugin.version";
return nil == name ? @"Unkown Plugin" : name; return nil == name ? @"Unkown Plugin" : name;
} }
- (NSString *)version { - (NSString *)humanVersionString {
return self.bundle.infoDictionary[@"CFBundleShortVersionString"];
}
- (NSString *)versionString {
if(self.bundle) { if(self.bundle) {
NSString *humanVersion = self.bundle.infoDictionary[@"CFBundleShortVersionString"]; NSString *humanVersion = self.humanVersionString;
NSString *version = self.bundle.infoDictionary[(NSString *)kCFBundleVersionKey]; NSString *version = self.bundle.infoDictionary[(NSString *)kCFBundleVersionKey];
if(humanVersion && version) { if(humanVersion && version) {
return [NSString stringWithFormat:@"%@ (%@)", humanVersion, version]; return [NSString stringWithFormat:@"%@ (%@)", humanVersion, version];

View File

@@ -48,6 +48,8 @@ FOUNDATION_EXPORT NSString *const MPPluginHostPluginBundleIdentifiyerKey;
- (void)disablePlugin:(MPPlugin *)plugin; - (void)disablePlugin:(MPPlugin *)plugin;
- (void)enablePlugin:(MPPlugin *)plugin; - (void)enablePlugin:(MPPlugin *)plugin;
- (void)loadPlugins;
/* /*
- (NSArray <MPPlugin __kindof*>*)autotypePlugins; - (NSArray <MPPlugin __kindof*>*)autotypePlugins;
- (NSArray <MPPlugin __kindof*>*)entryContextMenuPlugins; - (NSArray <MPPlugin __kindof*>*)entryContextMenuPlugins;

View File

@@ -26,6 +26,8 @@
#import "MPPlugin_Private.h" #import "MPPlugin_Private.h"
#import "MPPluginConstants.h" #import "MPPluginConstants.h"
#import "MPPluginEntryActionContext.h" #import "MPPluginEntryActionContext.h"
#import "MPPluginRepository.h"
#import "MPPluginRepositoryItem.h"
#import "NSApplication+MPAdditions.h" #import "NSApplication+MPAdditions.h"
#import "MPSettingsHelper.h" #import "MPSettingsHelper.h"
@@ -79,8 +81,6 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
_entryActionPluginIdentifiers = [[NSMutableArray alloc] init]; _entryActionPluginIdentifiers = [[NSMutableArray alloc] init];
_customAttributePluginIdentifiers = [[NSMutableArray alloc] init]; _customAttributePluginIdentifiers = [[NSMutableArray alloc] init];
[self _loadPlugins];
[self bind:NSStringFromSelector(@selector(loadUnsecurePlugins)) [self bind:NSStringFromSelector(@selector(loadUnsecurePlugins))
toObject:NSUserDefaultsController.sharedUserDefaultsController toObject:NSUserDefaultsController.sharedUserDefaultsController
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyLoadUnsecurePlugins] withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyLoadUnsecurePlugins]
@@ -94,7 +94,7 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
} }
- (NSString *)version { - (NSString *)version {
NSString *version = NSBundle.mainBundle.infoDictionary[(NSString *)kCFBundleVersionKey]; NSString *version = NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"];
return version; return version;
} }
@@ -131,7 +131,13 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
#pragma mark - Plugin Loading #pragma mark - Plugin Loading
- (void)_loadPlugins { - (void)loadPlugins {
[MPPluginRepository.defaultRepository fetchRepositoryDataCompletionHandler:^(NSArray<MPPluginRepositoryItem *> * _Nonnull availablePlugins) {
[self _loadPlugins:availablePlugins];
}];
}
- (void)_loadPlugins:(NSArray<MPPluginRepositoryItem *> *)availablePlugins {
NSURL *appSupportDir = [NSApp applicationSupportDirectoryURL:YES]; NSURL *appSupportDir = [NSApp applicationSupportDirectoryURL:YES];
NSError *error; NSError *error;
NSLog(@"Looking for external plugins at %@.", appSupportDir.path); NSLog(@"Looking for external plugins at %@.", appSupportDir.path);
@@ -190,6 +196,11 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
continue; continue;
} }
if(![self _isCompatiblePluginBundle:pluginBundle avaiablePlugins:availablePlugins ]) {
[self _addPluginForBundle:pluginBundle error:NSLocalizedString(@"PLUGIN_ERROR_HOST_VERSION_NOT_SUPPORTED", "Plugin is not with this version of MacPass")];
continue;
}
if(![pluginBundle loadAndReturnError:&error]) { if(![pluginBundle loadAndReturnError:&error]) {
NSLog(@"Bundle Loading Error %@ %@", error.localizedDescription, error.localizedFailureReason); NSLog(@"Bundle Loading Error %@ %@", error.localizedDescription, error.localizedFailureReason);
[self _addPluginForBundle:pluginBundle error:error.localizedDescription]; [self _addPluginForBundle:pluginBundle error:error.localizedDescription];
@@ -249,6 +260,17 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
return NO; return NO;
} }
- (BOOL)_isCompatiblePluginBundle:(NSBundle *)bundle avaiablePlugins:(NSArray<MPPluginRepositoryItem *> *)availablePlugins {
MPPluginRepositoryItem *repoItem;
for(MPPluginRepositoryItem *item in availablePlugins) {
if([item.bundleIdentifier isEqualToString:bundle.bundleIdentifier]) {
repoItem = item;
}
}
NSString *shortVersion = bundle.infoDictionary[@"CFBundleShortVersionString"];
return [repoItem isPluginVersion:shortVersion compatibleWithHost:self];
}
- (BOOL)_isValidPluginURL:(NSURL *)url { - (BOOL)_isValidPluginURL:(NSURL *)url {
return (NSOrderedSame == [url.pathExtension compare:MPPluginFileExtension options:NSCaseInsensitiveSearch]); return (NSOrderedSame == [url.pathExtension compare:MPPluginFileExtension options:NSCaseInsensitiveSearch]);
} }

View File

@@ -20,6 +20,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
NS_ASSUME_NONNULL_BEGIN
@import Foundation; @import Foundation;
@class MPPluginRepositoryItem; @class MPPluginRepositoryItem;
@@ -27,7 +29,9 @@
@interface MPPluginRepository : NSObject @interface MPPluginRepository : NSObject
@property (class, strong, readonly) MPPluginRepository *defaultRepository; @property (class, strong, readonly) MPPluginRepository *defaultRepository;
@property (nonatomic, copy) NSArray<MPPluginRepositoryItem *> *availablePlugins;
- (void)fetchRepositoryDataCompletionHandler:(void (^)(NSArray<MPPluginRepositoryItem *> *availablePlugins))completionHandler;
@end @end
NS_ASSUME_NONNULL_END

View File

@@ -24,9 +24,16 @@
#import "MPConstants.h" #import "MPConstants.h"
#import "MPPluginRepositoryItem.h" #import "MPPluginRepositoryItem.h"
@implementation MPPluginRepository const NSTimeInterval MPPluginRepositoryCacheTimeOut = 60*3; // 1 Minute cache time
@dynamic availablePlugins; @interface MPPluginRepository ()
@property NSTimeInterval lastPluginCheckTime;
@property BOOL didLoadData;
@end
@implementation MPPluginRepository
+ (instancetype)defaultRepository { + (instancetype)defaultRepository {
static MPPluginRepository *instance; static MPPluginRepository *instance;
@@ -39,38 +46,65 @@
- (instancetype)init { - (instancetype)init {
self = [super init]; self = [super init];
if(self) {
self.lastPluginCheckTime = NSDate.distantPast.timeIntervalSinceReferenceDate;
}
return self; return self;
} }
- (NSArray<MPPluginRepositoryItem *> *)availablePlugins { - (void)fetchRepositoryDataCompletionHandler:(void (^)(NSArray<MPPluginRepositoryItem *> * _Nonnull))completionHandler {
NSString *urlString = NSBundle.mainBundle.infoDictionary[MPBundlePluginRepositoryURLKey]; NSString *urlString = NSBundle.mainBundle.infoDictionary[MPBundlePluginRepositoryURLKey];
if(!urlString) { if(!urlString) {
return @[]; if(completionHandler) {
completionHandler(@[]);
}
return;
} }
NSURL *jsonURL = [NSURL URLWithString:urlString]; NSURL *jsonURL = [NSURL URLWithString:urlString];
if(!jsonURL) { if(!jsonURL) {
return @[]; if(completionHandler) {
} completionHandler(@[]);
NSError *error;
NSData *jsonData = [NSData dataWithContentsOfURL:jsonURL options:0 error:&error];
if(!jsonData) {
return @[];
}
id jsonRoot = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
if(!jsonRoot || ![jsonRoot isKindOfClass:NSArray.class]) {
return @[];
}
NSMutableArray *items = [[NSMutableArray alloc] init];
for(id item in jsonRoot) {
if(![item isKindOfClass:NSDictionary.class]) {
continue;
}
MPPluginRepositoryItem *pluginItem = [MPPluginRepositoryItem pluginItemFromDictionary:item];
if(pluginItem.isVaid) {
[items addObject:pluginItem];
} }
return;
} }
return [items copy];
NSURLSessionTask *downloadTask = [NSURLSession.sharedSession dataTaskWithURL:jsonURL completionHandler:^(NSData * _Nullable jsonData, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if(![response isKindOfClass:NSHTTPURLResponse.class]) {
if(completionHandler) {
completionHandler(@[]);
}
return;
}
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if(httpResponse.statusCode != 200 || jsonData.length == 0) {
if(completionHandler) {
completionHandler(@[]);
}
return;
}
id jsonRoot = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
if(!jsonRoot || ![jsonRoot isKindOfClass:NSArray.class]) {
if(completionHandler) {
completionHandler(@[]);
}
return;
}
NSMutableArray *items = [[NSMutableArray alloc] init];
for(id item in jsonRoot) {
if(![item isKindOfClass:NSDictionary.class]) {
continue;
}
MPPluginRepositoryItem *pluginItem = [MPPluginRepositoryItem pluginItemFromDictionary:item];
if(pluginItem.isVaid) {
[items addObject:pluginItem];
}
}
if(completionHandler) {
completionHandler([items copy]);
}
}];
[downloadTask resume];
} }
@end @end

View File

@@ -22,18 +22,26 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class MPPluginHost;
@interface MPPluginRepositoryItem : NSObject @interface MPPluginRepositoryItem : NSObject
@property (copy,readonly) NSString *name;
@property (copy,readonly) NSString *currentVersion; @property (copy,readonly, nullable) NSString *name;
@property (copy,readonly) NSString *descriptionText; @property (copy,readonly, nullable) NSString *currentVersion;
@property (copy,readonly) NSURL *sourceURL; @property (copy,readonly, nullable) NSString *descriptionText;
@property (copy,readonly) NSURL *downloadURL; @property (copy,readonly, nullable) NSURL *sourceURL;
@property (copy,readonly) NSURL *bundleIdentifier; @property (copy,readonly, nullable) NSURL *downloadURL;
@property (copy,readonly, nullable) NSString *bundleIdentifier;
@property (readonly, nonatomic, getter=isVaid) BOOL valid; @property (readonly, nonatomic, getter=isVaid) BOOL valid;
+ (instancetype)pluginItemFromDictionary:(NSDictionary *)dict; + (instancetype)pluginItemFromDictionary:(NSDictionary *)dict;
- (instancetype)initWithDictionary:(NSDictionary *)dict; - (instancetype)initWithDictionary:(NSDictionary *)dict;
- (BOOL)isPluginVersion:(NSString * _Nullable )pluginVersionString compatibleWithHost:(MPPluginHost *)host;
@end @end
NS_ASSUME_NONNULL_END

View File

@@ -21,6 +21,11 @@
// //
#import "MPPluginRepositoryItem.h" #import "MPPluginRepositoryItem.h"
#import "MPPluginRepositoryItemVersionInfo.h"
#import "MPPluginVersion.h"
#import "MPPluginHost.h"
#import "MPPlugin.h"
#import "NSError+Messages.h"
NSString *const MPPluginItemNameKey = @"name"; NSString *const MPPluginItemNameKey = @"name";
@@ -29,6 +34,7 @@ NSString *const MPPluginItemDownloadURLKey = @"download";
NSString *const MPPluginItemSourceURLKey = @"source"; NSString *const MPPluginItemSourceURLKey = @"source";
NSString *const MPPluginItemCurrentVersionKey = @"currentVersion"; NSString *const MPPluginItemCurrentVersionKey = @"currentVersion";
NSString *const MPPluginItemBundleIdentifierKey = @"bundleIdentifier"; NSString *const MPPluginItemBundleIdentifierKey = @"bundleIdentifier";
NSString *const MPPluginItemCompatibiltyKey = @"compatibilty";
@interface MPPluginRepositoryItem () @interface MPPluginRepositoryItem ()
@@ -37,7 +43,9 @@ NSString *const MPPluginItemBundleIdentifierKey = @"bundleIdentifier";
@property (copy) NSString *descriptionText; @property (copy) NSString *descriptionText;
@property (copy) NSURL *sourceURL; @property (copy) NSURL *sourceURL;
@property (copy) NSURL *downloadURL; @property (copy) NSURL *downloadURL;
@property (copy) NSURL *bundleIdentifier; @property (copy) NSString *bundleIdentifier;
@property (copy) NSArray *compatibilty;
@end @end
@@ -58,6 +66,8 @@ NSString *const MPPluginItemBundleIdentifierKey = @"bundleIdentifier";
self.sourceURL = [NSURL URLWithString:dict[MPPluginItemSourceURLKey]]; self.sourceURL = [NSURL URLWithString:dict[MPPluginItemSourceURLKey]];
self.currentVersion = dict[MPPluginItemCurrentVersionKey]; self.currentVersion = dict[MPPluginItemCurrentVersionKey];
self.bundleIdentifier = dict[MPPluginItemBundleIdentifierKey]; self.bundleIdentifier = dict[MPPluginItemBundleIdentifierKey];
[self _buildVersionInfos:dict[MPPluginItemCompatibiltyKey]];
} }
return self; return self;
} }
@@ -67,4 +77,50 @@ NSString *const MPPluginItemBundleIdentifierKey = @"bundleIdentifier";
return (self.name.length > 0 && self.downloadURL); return (self.name.length > 0 && self.downloadURL);
} }
- (BOOL)isPluginVersion:(NSString *)pluginVersionString compatibleWithHost:(MPPluginHost *)host {
if(pluginVersionString.length == 0) {
return NO;
}
MPPluginVersion *pluginVersion = [MPPluginVersion versionWithVersionString:pluginVersionString];
if(!pluginVersion) {
return NO;
}
if(host.version.length == 0) {
return NO;
}
MPPluginVersion *hostVersion = [MPPluginVersion versionWithVersionString:host.version];
if(!hostVersion) {
return NO;
}
NSMutableArray<MPPluginRepositoryItemVersionInfo *> *matches = [[NSMutableArray alloc] init];
for(MPPluginRepositoryItemVersionInfo *info in self.compatibilty) {
if(NSOrderedSame == [info.version compare:pluginVersion]) {
[matches addObject:info];
}
}
if(matches.count != 1) {
return NO;
}
MPPluginRepositoryItemVersionInfo *matchingInfo = matches.firstObject;
return [matchingInfo isCompatibleWithHostVersion:hostVersion];
}
- (void)_buildVersionInfos:(NSArray<NSDictionary *>*)infos {
NSMutableArray *tmp = [[NSMutableArray alloc] init];
for(NSDictionary *dict in infos) {
if(![dict isKindOfClass:NSDictionary.class]) {
continue;
}
MPPluginRepositoryItemVersionInfo *info = [MPPluginRepositoryItemVersionInfo versionInfoWithDict:dict];
if(info){
[tmp addObject:info];
}
}
self.compatibilty = [tmp copy];
}
@end @end

View File

@@ -10,11 +10,19 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class MPPluginVersion;
@interface MPPluginRepositoryItemVersionInfo : NSObject @interface MPPluginRepositoryItemVersionInfo : NSObject
@property (copy, readonly) MPPluginVersion *version;
+ (instancetype)versionInfoWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict NS_DESIGNATED_INITIALIZER; - (instancetype)initWithDict:(NSDictionary *)dict NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE;
- (BOOL)isCompatibleWithHostVersion:(MPPluginVersion *)hostVersion;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@@ -7,30 +7,75 @@
// //
#import "MPPluginRepositoryItemVersionInfo.h" #import "MPPluginRepositoryItemVersionInfo.h"
#import "MPPluginVersion.h"
NSString *const MPPluginItemCompatibiltyVersionKey = @"pluginVersion"; NSString *const MPPluginItemCompatibiltyVersionKey = @"pluginVersion";
NSString *const MPPluginItemCompatibiltyMinimumHostVersionKey = @"minimumHostVersion"; NSString *const MPPluginItemCompatibiltyMinimumHostVersionKey = @"minimumHostVersion";
NSString *const MPPluginItemCompatibiltyMaxiumumHostVersionKey = @"maxiumumHostVersion"; NSString *const MPPluginItemCompatibiltyMaxiumumHostVersionKey = @"maximumHostVersion";
@interface MPPluginRepositoryItemVersionInfo () @interface MPPluginRepositoryItemVersionInfo ()
@property (copy) NSString *version; @property (copy) MPPluginVersion *version;
@property (copy) NSString *minimumHostVersion; @property (copy) MPPluginVersion *minimumHostVersion;
@property (copy) NSString *maxiumHostVersion; @property (copy) MPPluginVersion *maxiumHostVersion;
@end @end
@implementation MPPluginRepositoryItemVersionInfo @implementation MPPluginRepositoryItemVersionInfo
+ (instancetype)versionInfoWithDict:(NSDictionary *)dict {
return [[MPPluginRepositoryItemVersionInfo alloc] initWithDict:dict];
}
- (instancetype)initWithDict:(NSDictionary *)dict { - (instancetype)initWithDict:(NSDictionary *)dict {
self = [super init]; self = [super init];
if(self) { if(self) {
self.version = dict[MPPluginItemCompatibiltyVersionKey]; NSString *versionString = dict[MPPluginItemCompatibiltyVersionKey];
self.minimumHostVersion = dict[MPPluginItemCompatibiltyMinimumHostVersionKey]; if(!versionString) {
self.maxiumHostVersion = dict[MPPluginItemCompatibiltyMaxiumumHostVersionKey]; NSLog(@"Version information is missing required %@ key.", MPPluginItemCompatibiltyVersionKey);
self = nil;
return self;
}
self.version = [MPPluginVersion versionWithVersionString:versionString];
if(!self.version) {
NSLog(@"Malformed plugin version information: %@.", versionString);
self = nil;
return self;
}
NSString *minimumHostVersionString = dict[MPPluginItemCompatibiltyMinimumHostVersionKey];
if(!minimumHostVersionString) {
NSLog(@"Version information is missing required %@ key.", MPPluginItemCompatibiltyMinimumHostVersionKey);
self = nil;
return self;
}
self.minimumHostVersion = [MPPluginVersion versionWithVersionString:minimumHostVersionString];
if(!self.minimumHostVersion) {
NSLog(@"Malformed minimum host version information: %@.", minimumHostVersionString);
self = nil;
return self;
}
NSString *maxiumHostVersionString = dict[MPPluginItemCompatibiltyMaxiumumHostVersionKey];
if(maxiumHostVersionString) {
self.maxiumHostVersion = [MPPluginVersion versionWithVersionString:maxiumHostVersionString];
if(!self.maxiumHostVersion) {
NSLog(@"Malformed maxium host version information: %@.", maxiumHostVersionString);
self = nil;
return self;
}
}
} }
return self; return self;
} }
- (BOOL)isCompatibleWithHostVersion:(MPPluginVersion *)hostVersion {
if(NSOrderedDescending == [self.minimumHostVersion compare:hostVersion]) {
return NO;
}
if(!self.maxiumHostVersion) {
return YES;
}
return (NSOrderedAscending != [self.maxiumHostVersion compare:hostVersion]);
}
@end @end

View File

@@ -26,6 +26,8 @@
#import "MPPlugin.h" #import "MPPlugin.h"
#import "MPPlugin_Private.h" #import "MPPlugin_Private.h"
#import "MPPluginConstants.h" #import "MPPluginConstants.h"
#import "MPPluginRepository.h"
#import "MPPluginRepositoryItem.h"
#import "MPConstants.h" #import "MPConstants.h"
#import "MPSettingsHelper.h" #import "MPSettingsHelper.h"
@@ -96,7 +98,7 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
? [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_NAME_ERROR_%@", "Name for unloaded plugin with errors"), plugin.name] ? [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_NAME_ERROR_%@", "Name for unloaded plugin with errors"), plugin.name]
: [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_NAME_DISABLED_%@", "name for disabled unloaded plugin"), plugin.name]); : [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_NAME_DISABLED_%@", "name for disabled unloaded plugin"), plugin.name]);
} }
view.addionalTextField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_VERSION_%@", "Plugin version. Include a %@ placeholder for version string"), plugin.version]; view.addionalTextField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_VERSION_%@", "Plugin version. Include a %@ placeholder for version string"), plugin.versionString];
return view; return view;
} }

31
MacPass/MPPluginVersion.h Normal file
View File

@@ -0,0 +1,31 @@
//
// MPPluginVersion.h
// MacPass
//
// Created by Michael Starke on 05.10.18.
// Copyright © 2018 HicknHack Software GmbH. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
FOUNDATION_EXPORT NSString *MPPluginVersionWildcard;
@interface MPPluginVersion : NSObject <NSCopying>
@property (nonatomic, copy, readonly) NSString *versionString;
@property (nonatomic, copy, readonly) NSString *mayorVersion;
@property (nonatomic, copy, readonly) NSString *minorVersion;
@property (nonatomic, copy, readonly) NSString *patchVersion;
+ (instancetype)versionWithVersionString:(NSString *)versionString;
- (instancetype)initWithVersionString:(NSString *)versionString NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
- (NSComparisonResult)compare:(MPPluginVersion *)version;
@end
NS_ASSUME_NONNULL_END

122
MacPass/MPPluginVersion.m Normal file
View File

@@ -0,0 +1,122 @@
//
// MPPluginVersion.m
// MacPass
//
// Created by Michael Starke on 05.10.18.
// Copyright © 2018 HicknHack Software GmbH. All rights reserved.
//
#import "MPPluginVersion.h"
NSString *MPPluginVersionWildcard = @"*";
@interface MPPluginVersion ()
@property (nonatomic, copy) NSString *versionString;
@property (nonatomic, copy) NSString *mayorVersion;
@property (nonatomic, copy) NSString *minorVersion;
@property (nonatomic, copy) NSString *patchVersion;
@end
@implementation MPPluginVersion
+ (instancetype)versionWithVersionString:(NSString *)versionString {
return [[MPPluginVersion alloc] initWithVersionString:versionString];
}
- (instancetype)initWithVersionString:(NSString *)versionString {
self = [super init];
if(self) {
self.mayorVersion = @"0";
self.minorVersion = @"0";
self.patchVersion = @"0";
NSArray<NSString *>* components = [versionString componentsSeparatedByString:@"."];
if(components.count >= 1) {
NSString *mayorVersion = components[0].length > 0 ? components[0] : @"0";
if([mayorVersion isEqualToString:MPPluginVersionWildcard]) {
self.mayorVersion = MPPluginVersionWildcard;
self.minorVersion = MPPluginVersionWildcard;
self.patchVersion = MPPluginVersionWildcard;
self.versionString = [NSString stringWithFormat:@"%@.%@.%@", self.mayorVersion, self.minorVersion, self.patchVersion];
return self;
}
NSCharacterSet *invalidSet = NSCharacterSet.decimalDigitCharacterSet.invertedSet;
NSRange mayorRange = [mayorVersion rangeOfCharacterFromSet:invalidSet];
if(mayorRange.location != NSNotFound) {
NSLog(@"Invalid Format for Mayor Version");
self = nil;
return self;
}
self.mayorVersion = mayorVersion;
if(components.count >= 2) {
NSString *minorVersion = components[1].length > 0 ? components[1] : @"0";
if([minorVersion isEqualToString:MPPluginVersionWildcard]) {
self.minorVersion = MPPluginVersionWildcard;
self.patchVersion = MPPluginVersionWildcard;
self.versionString = [NSString stringWithFormat:@"%@.%@.%@", self.mayorVersion, self.minorVersion, self.patchVersion];
return self;
}
NSRange minorRange = [minorVersion rangeOfCharacterFromSet:invalidSet];
if(minorRange.location != NSNotFound) {
NSLog(@"Invalid Format for Minor Version");
self.versionString = [NSString stringWithFormat:@"%@.%@.%@", self.mayorVersion, self.minorVersion, self.patchVersion];
self = nil;
return self;
}
self.minorVersion = minorVersion;
if(components.count == 3) {
NSString *patchVersion = components[2].length > 0 ? components[2] : @"0";
if([patchVersion isEqualToString:MPPluginVersionWildcard]) {
self.patchVersion = MPPluginVersionWildcard;
self.versionString = [NSString stringWithFormat:@"%@.%@.%@", self.mayorVersion, self.minorVersion, self.patchVersion];
return self;
}
NSRange patchRange = [patchVersion rangeOfCharacterFromSet:invalidSet];
if(patchRange.location != NSNotFound) {
NSLog(@"Invalid Format for Patch Version");
self = nil;
return self;
}
self.patchVersion = patchVersion;
}
}
}
self.versionString = [NSString stringWithFormat:@"%@.%@.%@", self.mayorVersion, self.minorVersion, self.patchVersion];
}
return self;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (NSComparisonResult)compare:(MPPluginVersion *)version {
if([self.versionString isEqualToString:version.versionString]) {
return NSOrderedSame;
}
NSArray<NSString *> *myVersions = @[self.mayorVersion, self.minorVersion, self.patchVersion];
NSArray<NSString *> *otherVersions = @[version.mayorVersion, version.minorVersion, version.patchVersion];
for(NSUInteger index = 0; index < 3; index++) {
NSString *myVersion = myVersions[index];
NSString *otherVersion = otherVersions[index];
if([myVersion isEqualToString:MPPluginVersionWildcard] || [otherVersion isEqualToString:MPPluginVersionWildcard]) {
return NSOrderedSame;
}
NSComparisonResult compare = [myVersion compare:otherVersion options:NSNumericSearch|NSCaseInsensitiveSearch];
if(compare != NSOrderedSame) {
return compare;
}
}
return NSOrderedSame;
}
@end

View File

@@ -0,0 +1,150 @@
//
// MPTestPluginVersion.m
// MacPassTests
//
// Created by Michael Starke on 05.10.18.
// Copyright © 2018 HicknHack Software GmbH. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "MPPluginVersion.h"
@interface MPTestPluginVersion : XCTestCase
@end
@implementation MPTestPluginVersion
- (void)testVersionExtraction {
MPPluginVersion *version = [[MPPluginVersion alloc] initWithVersionString:@"1."];
XCTAssertEqualObjects(@"1", version.mayorVersion);
XCTAssertEqualObjects(@"0", version.minorVersion);
XCTAssertEqualObjects(@"0", version.patchVersion);
XCTAssertEqualObjects(@"1.0.0", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"0.5"];
XCTAssertEqualObjects(@"0", version.mayorVersion);
XCTAssertEqualObjects(@"5", version.minorVersion);
XCTAssertEqualObjects(@"0", version.patchVersion);
XCTAssertEqualObjects(@"0.5.0", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@".5"];
XCTAssertEqualObjects(@"0", version.mayorVersion);
XCTAssertEqualObjects(@"5", version.minorVersion);
XCTAssertEqualObjects(@"0", version.patchVersion);
XCTAssertEqualObjects(@"0.5.0", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"5"];
XCTAssertEqualObjects(@"5", version.mayorVersion);
XCTAssertEqualObjects(@"0", version.minorVersion);
XCTAssertEqualObjects(@"0", version.patchVersion);
XCTAssertEqualObjects(@"5.0.0", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@".1."];
XCTAssertEqualObjects(@"0", version.mayorVersion);
XCTAssertEqualObjects(@"1", version.minorVersion);
XCTAssertEqualObjects(@"0", version.patchVersion);
XCTAssertEqualObjects(@"0.1.0", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@".1.1"];
XCTAssertEqualObjects(@"0", version.mayorVersion);
XCTAssertEqualObjects(@"1", version.minorVersion);
XCTAssertEqualObjects(@"1", version.patchVersion);
XCTAssertEqualObjects(@"0.1.1", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"..1"];
XCTAssertEqualObjects(@"0", version.mayorVersion);
XCTAssertEqualObjects(@"0", version.minorVersion);
XCTAssertEqualObjects(@"1", version.patchVersion);
XCTAssertEqualObjects(@"0.0.1", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"1.0.0"];
XCTAssertEqualObjects(@"1", version.mayorVersion);
XCTAssertEqualObjects(@"0", version.minorVersion);
XCTAssertEqualObjects(@"0", version.patchVersion);
XCTAssertEqualObjects(@"1.0.0", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"0.1.0"];
XCTAssertEqualObjects(@"0", version.mayorVersion);
XCTAssertEqualObjects(@"1", version.minorVersion);
XCTAssertEqualObjects(@"0", version.patchVersion);
XCTAssertEqualObjects(@"0.1.0", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"1.1.1"];
XCTAssertEqualObjects(@"1", version.mayorVersion);
XCTAssertEqualObjects(@"1", version.minorVersion);
XCTAssertEqualObjects(@"1", version.patchVersion);
XCTAssertEqualObjects(@"1.1.1", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"0.0.5"];
XCTAssertEqualObjects(@"0", version.mayorVersion);
XCTAssertEqualObjects(@"0", version.minorVersion);
XCTAssertEqualObjects(@"5", version.patchVersion);
XCTAssertEqualObjects(@"0.0.5", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"1.0.3"];
XCTAssertEqualObjects(@"1", version.mayorVersion);
XCTAssertEqualObjects(@"0", version.minorVersion);
XCTAssertEqualObjects(@"3", version.patchVersion);
XCTAssertEqualObjects(@"1.0.3", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"0.1.4"];
XCTAssertEqualObjects(@"0", version.mayorVersion);
XCTAssertEqualObjects(@"1", version.minorVersion);
XCTAssertEqualObjects(@"4", version.patchVersion);
XCTAssertEqualObjects(@"0.1.4", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"0.1.*"];
XCTAssertEqualObjects(@"0", version.mayorVersion);
XCTAssertEqualObjects(@"1", version.minorVersion);
XCTAssertEqualObjects(@"*", version.patchVersion);
XCTAssertEqualObjects(@"0.1.*", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"*.1.0"];
XCTAssertEqualObjects(@"*", version.mayorVersion);
XCTAssertEqualObjects(@"*", version.minorVersion);
XCTAssertEqualObjects(@"*", version.patchVersion);
XCTAssertEqualObjects(@"*.*.*", version.versionString);
version = [[MPPluginVersion alloc] initWithVersionString:@"1.*.0"];
XCTAssertEqualObjects(@"1", version.mayorVersion);
XCTAssertEqualObjects(@"*", version.minorVersion);
XCTAssertEqualObjects(@"*", version.patchVersion);
XCTAssertEqualObjects(@"1.*.*", version.versionString);
}
- (void)testeVersionCompare {
NSArray *data = @[
@[ @"*", @"*", @(NSOrderedSame)],
@[ @"1.0.1", @"*", @(NSOrderedSame)],
@[ @"*", @"1.0.1", @(NSOrderedSame)],
@[ @"1.*", @"1.*", @(NSOrderedSame)],
@[ @"1.1.*", @"1.1.*", @(NSOrderedSame)],
@[ @"1.1.1", @"1.1.1", @(NSOrderedSame)],
@[ @"1.0.1", @"*", @(NSOrderedSame)],
@[ @"0.10.*", @"0.10.1", @(NSOrderedSame)],
@[ @"10.*.1", @"10.99.*", @(NSOrderedSame)],
@[ @"0.9.89", @"0.9.89", @(NSOrderedSame)],
@[ @"0.0.1", @"0.0.2", @(NSOrderedAscending)],
@[ @"1.10.10", @"1.12.10", @(NSOrderedAscending)],
@[ @"20.0.1", @"20.1.0", @(NSOrderedAscending)],
@[ @"1.1.1", @"2.*", @(NSOrderedAscending)],
@[ @"1.*", @"2.0.*", @(NSOrderedAscending)],
@[ @"2.1.1", @"2.0.0", @(NSOrderedDescending)],
@[ @"0.1.1", @"0.1.0", @(NSOrderedDescending)],
@[ @"1.2.*", @"1.1.*", @(NSOrderedDescending)],
@[ @"2.*", @"1.*", @(NSOrderedDescending)]
];
for(NSUInteger index = 0; index < data.count; index++) {
NSArray *set = data[index];
MPPluginVersion *versionA = [[MPPluginVersion alloc] initWithVersionString:set[0]];
MPPluginVersion *versionB = [[MPPluginVersion alloc] initWithVersionString:set[1]];
NSComparisonResult result = [set[2] integerValue];
XCTAssertEqual(result, [versionA compare:versionB]);
}
}
@end