Reverting back to string based version compare. Using customized comparator based ond Sparkle verison compare

This commit is contained in:
Michael Starke
2018-10-24 16:07:38 +02:00
parent 20ed81a5e7
commit 3cd8d07552
23 changed files with 495 additions and 470 deletions

View File

@@ -148,8 +148,8 @@
4C6F228C19A4AA700012310C /* MPAutotypeDelay.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6F228B19A4AA700012310C /* MPAutotypeDelay.m */; };
4C701CBC178618A000581B88 /* 12_RemoteTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C701CBB178618A000581B88 /* 12_RemoteTemplate.pdf */; };
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 */; };
4C71BCB42167B75900B4CBDA /* MPTestPluginVersionComparator.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C71BCB32167B75900B4CBDA /* MPTestPluginVersionComparator.m */; };
4C71BCB72167B79C00B4CBDA /* MPPluginVersionComparator.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C71BCB62167B79C00B4CBDA /* MPPluginVersionComparator.m */; };
4C735FC02035FCBF00708D53 /* MPPluginEntryActionContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C735FBF2035FCBF00708D53 /* MPPluginEntryActionContext.m */; };
4C73B6F1215E64A7009787F7 /* MPWelcomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C73B6EF215E64A7009787F7 /* MPWelcomeViewController.m */; };
4C76155C1764C04C0015A1A6 /* GeneralSettings.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C76155E1764C04C0015A1A6 /* GeneralSettings.xib */; };
@@ -578,9 +578,9 @@
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>"; };
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>"; };
4C71BCB32167B75900B4CBDA /* MPTestPluginVersionComparator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPTestPluginVersionComparator.m; sourceTree = "<group>"; };
4C71BCB52167B79C00B4CBDA /* MPPluginVersionComparator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPluginVersionComparator.h; sourceTree = "<group>"; };
4C71BCB62167B79C00B4CBDA /* MPPluginVersionComparator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPluginVersionComparator.m; 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>"; };
4C73B6EE215E64A7009787F7 /* MPWelcomeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPWelcomeViewController.h; sourceTree = "<group>"; };
@@ -1207,7 +1207,7 @@
4C6BC65F1A36717E00BDDF3D /* MPDatabaseSearch.m */,
4C8030491E2FBAA300133E4C /* MPTestKeyMapper.m */,
4C8F0C721FCF1B7A00BE157F /* MPTestPickcharsParser.m */,
4C71BCB32167B75900B4CBDA /* MPTestPluginVersion.m */,
4C71BCB32167B75900B4CBDA /* MPTestPluginVersionComparator.m */,
4C45FB1F178E09ED0010007D /* Supporting Files */,
);
path = MacPassTests;
@@ -1684,8 +1684,8 @@
4C81867C216664C70068DAFB /* MPPluginRepositoryItemVersionInfo.m */,
4C735FBE2035FCBF00708D53 /* MPPluginEntryActionContext.h */,
4C735FBF2035FCBF00708D53 /* MPPluginEntryActionContext.m */,
4C71BCB52167B79C00B4CBDA /* MPPluginVersion.h */,
4C71BCB62167B79C00B4CBDA /* MPPluginVersion.m */,
4C71BCB52167B79C00B4CBDA /* MPPluginVersionComparator.h */,
4C71BCB62167B79C00B4CBDA /* MPPluginVersionComparator.m */,
);
name = Plugin;
path = MacPass;
@@ -1935,7 +1935,7 @@
files = (
4C45FB2D178E0BCB0010007D /* MPDatabaseLoading.m in Sources */,
4C8DEAA21C314D2C00D24C32 /* MPTestAutotypeDelay.m in Sources */,
4C71BCB42167B75900B4CBDA /* MPTestPluginVersion.m in Sources */,
4C71BCB42167B75900B4CBDA /* MPTestPluginVersionComparator.m in Sources */,
4C8F0C731FCF1B7A00BE157F /* MPTestPickcharsParser.m in Sources */,
4C45FB30178E0CE20010007D /* MPTestDocument.m in Sources */,
4C6BC6601A36717E00BDDF3D /* MPDatabaseSearch.m in Sources */,
@@ -2059,7 +2059,7 @@
4C1FA07B18231900003A3F8C /* MPDocument+Autotype.m in Sources */,
4C4B7EE917A45EC6000234C7 /* MPDatePickingViewController.m in Sources */,
4C4B7EEE17A467E1000234C7 /* MPGroupInspectorViewController.m in Sources */,
4C71BCB72167B79C00B4CBDA /* MPPluginVersion.m in Sources */,
4C71BCB72167B79C00B4CBDA /* MPPluginVersionComparator.m in Sources */,
4C7B63721C0CB51F00D7038C /* TTTCryptographyTransformers.m in Sources */,
4C4B7EF317A467FC000234C7 /* MPEntryInspectorViewController.m in Sources */,
4C1BDF2B1E4392640012A3F0 /* MPPluginDataViewController.m in Sources */,

View File

@@ -1,9 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13529"/>
<capability name="box content view" minToolsVersion="7.0"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14313.18"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -12,6 +11,7 @@
<outlet property="addRemovePluginsControl" destination="B9Q-hq-K4N" id="Oqj-Ko-8UR"/>
<outlet property="fallbackDescriptionTextField" destination="qPL-FR-ky7" id="xCb-ED-NIX"/>
<outlet property="fallbackSettingsView" destination="wIk-iw-Tcz" id="dHl-zW-0aI"/>
<outlet property="forceIncompatiblePluginsCheckButton" destination="XIl-03-JZP" id="Aj4-rc-Ao0"/>
<outlet property="loadInsecurePlugsinCheckButton" destination="CqP-oK-S8k" id="YET-o6-7Cc"/>
<outlet property="pluginTableView" destination="Ocu-C0-03d" id="jbH-qr-bVT"/>
<outlet property="settingsView" destination="tD5-Na-7XI" id="Pa0-Tt-20U"/>
@@ -21,19 +21,19 @@
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Hz6-mo-xeY">
<rect key="frame" x="0.0" y="0.0" width="520" height="473"/>
<rect key="frame" x="0.0" y="0.0" width="600" height="473"/>
<subviews>
<box borderType="line" title="Box" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="vBs-Ga-aq0">
<rect key="frame" x="175" y="46" width="328" height="351"/>
<rect key="frame" x="175" y="46" width="408" height="321"/>
<view key="contentView" id="tD5-Na-7XI">
<rect key="frame" x="1" y="1" width="326" height="349"/>
<rect key="frame" x="1" y="1" width="406" height="319"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="wIk-iw-Tcz">
<rect key="frame" x="20" y="20" width="286" height="309"/>
<rect key="frame" x="20" y="20" width="366" height="279"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qPL-FR-ky7">
<rect key="frame" x="18" y="272" width="122" height="17"/>
<rect key="frame" x="18" y="242" width="330" height="17"/>
<textFieldCell key="cell" controlSize="mini" sendsActionOnEndEditing="YES" title="Plugin Settings Info" id="OOr-SW-jZb">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -43,7 +43,7 @@
</subviews>
<constraints>
<constraint firstItem="qPL-FR-ky7" firstAttribute="top" secondItem="wIk-iw-Tcz" secondAttribute="top" constant="20" symbolic="YES" id="BAH-sF-W03"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="qPL-FR-ky7" secondAttribute="trailing" constant="20" symbolic="YES" id="HKa-7h-OiN"/>
<constraint firstAttribute="trailing" secondItem="qPL-FR-ky7" secondAttribute="trailing" constant="20" symbolic="YES" id="HKa-7h-OiN"/>
<constraint firstItem="qPL-FR-ky7" firstAttribute="leading" secondItem="wIk-iw-Tcz" secondAttribute="leading" constant="20" symbolic="YES" id="UTY-Lu-pvl"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="qPL-FR-ky7" secondAttribute="bottom" constant="20" symbolic="YES" id="wpb-76-pxa"/>
</constraints>
@@ -65,7 +65,7 @@
</buttonCell>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aoG-FD-ds8">
<rect key="frame" x="18" y="403" width="484" height="28"/>
<rect key="frame" x="18" y="403" width="564" height="28"/>
<textFieldCell key="cell" controlSize="small" sendsActionOnEndEditing="YES" id="2bX-8S-9XM">
<font key="font" metaFont="smallSystem"/>
<string key="title">If enabled, Plugins without proper signatures will be allowed to load. Keep in mind, that Plugins have full access to your data! Changes take affect on restart.</string>
@@ -74,13 +74,13 @@
</textFieldCell>
</textField>
<scrollView autohidesScrollers="YES" horizontalLineScroll="37" horizontalPageScroll="10" verticalLineScroll="37" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fCk-fL-jU8">
<rect key="frame" x="20" y="50" width="150" height="345"/>
<rect key="frame" x="20" y="50" width="150" height="315"/>
<clipView key="contentView" id="lTL-Q2-k45">
<rect key="frame" x="1" y="1" width="148" height="343"/>
<rect key="frame" x="1" y="1" width="148" height="313"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnSelection="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="35" rowSizeStyle="automatic" viewBased="YES" id="Ocu-C0-03d">
<rect key="frame" x="0.0" y="0.0" width="148" height="343"/>
<rect key="frame" x="0.0" y="0.0" width="148" height="313"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@@ -154,7 +154,7 @@
</scroller>
</scrollView>
<segmentedControl verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="B9Q-hq-K4N">
<rect key="frame" x="20" y="18" width="67" height="25"/>
<rect key="frame" x="20" y="19" width="71" height="23"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="texturedSquare" trackingMode="momentary" id="cj3-R6-g1E">
<font key="font" metaFont="system"/>
<segments>
@@ -167,7 +167,7 @@
</connections>
</segmentedControl>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="SNe-cc-CZs">
<rect key="frame" x="383" y="18" width="117" height="25"/>
<rect key="frame" x="463" y="18" width="117" height="25"/>
<buttonCell key="cell" type="roundTextured" title="Browse Plugins…" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="sqO-8H-n1y">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@@ -176,9 +176,17 @@
<action selector="browsePlugins:" target="-2" id="16S-2u-Tmi"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="XIl-03-JZP">
<rect key="frame" x="18" y="371" width="250" height="18"/>
<buttonCell key="cell" type="check" title="Force loading of incompatible Plugins" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="yak-fS-jtA">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstItem="CqP-oK-S8k" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" id="1Rj-zS-7t2"/>
<constraint firstItem="XIl-03-JZP" firstAttribute="top" secondItem="aoG-FD-ds8" secondAttribute="bottom" constant="16" id="2Wk-4D-AHu"/>
<constraint firstItem="vBs-Ga-aq0" firstAttribute="top" secondItem="fCk-fL-jU8" secondAttribute="top" id="2h6-C9-4N5"/>
<constraint firstItem="B9Q-hq-K4N" firstAttribute="top" secondItem="fCk-fL-jU8" secondAttribute="bottom" constant="8" symbolic="YES" id="3vA-Oh-cFO"/>
<constraint firstAttribute="bottom" secondItem="B9Q-hq-K4N" secondAttribute="bottom" constant="20" symbolic="YES" id="7HD-ji-Whc"/>
@@ -192,13 +200,15 @@
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="CqP-oK-S8k" secondAttribute="trailing" constant="20" symbolic="YES" id="TXL-mf-nxu"/>
<constraint firstItem="SNe-cc-CZs" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="B9Q-hq-K4N" secondAttribute="trailing" constant="8" symbolic="YES" id="a62-en-kDA"/>
<constraint firstItem="fCk-fL-jU8" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" id="fzW-4b-L8S"/>
<constraint firstItem="XIl-03-JZP" firstAttribute="leading" secondItem="CqP-oK-S8k" secondAttribute="leading" id="oqX-wa-jm0"/>
<constraint firstItem="SNe-cc-CZs" firstAttribute="top" secondItem="vBs-Ga-aq0" secondAttribute="bottom" constant="8" symbolic="YES" id="r4X-iM-iYU"/>
<constraint firstItem="CqP-oK-S8k" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" id="rN1-3Z-BBi"/>
<constraint firstItem="fCk-fL-jU8" firstAttribute="top" secondItem="aoG-FD-ds8" secondAttribute="bottom" constant="8" id="vl9-MY-WW1"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="XIl-03-JZP" secondAttribute="trailing" constant="20" symbolic="YES" id="rkN-ew-RtP"/>
<constraint firstItem="fCk-fL-jU8" firstAttribute="top" secondItem="XIl-03-JZP" secondAttribute="bottom" constant="8" symbolic="YES" id="vl9-MY-WW1"/>
<constraint firstItem="vBs-Ga-aq0" firstAttribute="leading" secondItem="fCk-fL-jU8" secondAttribute="trailing" constant="8" id="xNu-Sj-xQO"/>
<constraint firstItem="aoG-FD-ds8" firstAttribute="top" secondItem="CqP-oK-S8k" secondAttribute="bottom" constant="8" symbolic="YES" id="zSW-h3-BrT"/>
</constraints>
<point key="canvasLocation" x="-163" y="-18"/>
<point key="canvasLocation" x="110" y="-97"/>
</customView>
</objects>
<resources>

View File

@@ -28,7 +28,6 @@ NS_ASSUME_NONNULL_BEGIN
@class KPKEntry;
@class KPKAttribute;
@class KPKTree;
@class MPPluginVersion;
FOUNDATION_EXPORT NSString *const MPPluginUnkownVersion;
@@ -36,8 +35,7 @@ FOUNDATION_EXPORT NSString *const MPPluginUnkownVersion;
@property (copy, readonly) NSString *identifier;
@property (copy, readonly) NSString *name;
@property (nonatomic, copy, readonly, nullable) NSString *humanVersionString;
@property (nonatomic, copy, readonly, nullable) MPPluginVersion *version;
@property (nonatomic, copy, readonly, nullable) NSString *shortVersionString;
@property (nonatomic, copy, readonly) NSString *versionString;
@property (nonatomic, strong, readonly) NSBundle *bundle;
@@ -89,21 +87,12 @@ FOUNDATION_EXPORT NSString *const MPPluginUnkownVersion;
- (NSString *)initialValueForAttributeWithKey:(NSString *)key;
@end
@protocol MPExportPluginViewController <NSObject>
@protocol MPImportPlugin <NSObject>
@required
@property (nonatomic, copy) NSDictionary *exportOptions;
@property (readonly, copy) NSArray<NSString *> *supportedUTIs;
- (KPKTree *)importTreeWithContentsOfURL:(NSURL *)url;
@end
@protocol MPExportPlugin <NSObject>
@required
/* Ideally supply a list of Formats supported. This format specifier is used when being called */
@property (nonatomic, copy) NSDictionary<NSString *, NSString *>* localizedSuportedFormats;
- (NSData *)dataForTree:(KPKTree *)tree withFormat:(NSString *)format options:(NSDictionary *)options;
@optional
- (NSViewController<MPExportPluginViewController> *)exportViewControllerForTree:(KPKTree *)tree withFormat:(NSString *)format;
@end
@interface MPPlugin (Deprecated)
- (instancetype)initWithPluginManager:(id)manager;

View File

@@ -25,14 +25,13 @@
#import "MPPluginHost.h"
#import "MPSettingsHelper.h"
#import "MPPluginConstants.h"
#import "MPPluginVersion.h"
#import "MPPluginVersionComparator.h"
NSString *const MPPluginUnkownVersion = @"unkown.plugin.version";
@implementation MPPlugin
@synthesize bundle = _bundle;
@synthesize version = _version;
- (instancetype)initWithPluginHost:(MPPluginHost *)host {
self = [super init];
@@ -70,21 +69,13 @@ NSString *const MPPluginUnkownVersion = @"unkown.plugin.version";
return nil == name ? @"Unkown Plugin" : name;
}
- (NSString *)humanVersionString {
- (NSString *)shortVersionString {
return self.bundle.infoDictionary[@"CFBundleShortVersionString"];
}
- (MPPluginVersion *)version {
if(!_versionInitialized) {
_version = [MPPluginVersion versionWithVersionString:self.humanVersionString];
_versionInitialized = YES;
}
return _version;
}
- (NSString *)versionString {
if(self.bundle) {
NSString *humanVersion = self.humanVersionString;
NSString *humanVersion = self.shortVersionString;
NSString *version = self.bundle.infoDictionary[(NSString *)kCFBundleVersionKey];
if(humanVersion && version) {
return [NSString stringWithFormat:@"%@ (%@)", humanVersion, version];

View File

@@ -31,14 +31,14 @@ FOUNDATION_EXPORT NSString *const MPPluginHostPluginBundleIdentifiyerKey;
@class MPPlugin;
@class KPKEntry;
@class MPPluginVersion;
@protocol MPImportPlugin;
@interface MPPluginHost : NSObject
/* List of all plugins known to the plugin manager. Disabled plugins are also present! */
@property (readonly, copy) NSArray <MPPlugin __kindof*> *plugins;
@property (nonatomic, readonly) BOOL loadUnsecurePlugins;
@property (readonly, copy) MPPluginVersion *version;
@property (readonly, copy) NSArray <MPPlugin __kindof*> *importPlugins;
@property (nonatomic, readonly, copy) NSString *version;
+ (instancetype)sharedHost;

View File

@@ -28,7 +28,7 @@
#import "MPPluginEntryActionContext.h"
#import "MPPluginRepository.h"
#import "MPPluginRepositoryItem.h"
#import "MPPluginVersion.h"
#import "MPPluginVersionComparator.h"
#import "NSApplication+MPAdditions.h"
#import "MPSettingsHelper.h"
@@ -48,10 +48,6 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
@property (strong) NSMutableArray<NSString *> *entryActionPluginIdentifiers;
@property (strong) NSMutableArray<NSString *> *customAttributePluginIdentifiers;
@property (nonatomic) BOOL loadUnsecurePlugins;
@property (copy) NSArray<NSString *> *disabledPlugins;
@end
@implementation MPPluginHost
@@ -77,28 +73,27 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
self = [super init];
if(self) {
_mutablePlugins = [[NSMutableArray alloc] init];
_disabledPlugins = [NSUserDefaults.standardUserDefaults arrayForKey:kMPSettingsKeyLoadUnsecurePlugins];
_loadUnsecurePlugins = [NSUserDefaults.standardUserDefaults boolForKey:kMPSettingsKeyLoadUnsecurePlugins];
_entryActionPluginIdentifiers = [[NSMutableArray alloc] init];
_customAttributePluginIdentifiers = [[NSMutableArray alloc] init];
_version = [[MPPluginVersion alloc] initWithVersionString:NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"]];
[self bind:NSStringFromSelector(@selector(loadUnsecurePlugins))
toObject:NSUserDefaultsController.sharedUserDefaultsController
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyLoadUnsecurePlugins]
options:nil];
[self bind:NSStringFromSelector(@selector(disabledPlugins))
toObject:NSUserDefaultsController.sharedUserDefaultsController
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyDisabledPlugins]
options:nil];
}
return self;
}
- (NSString *)version {
return NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"];
}
- (NSArray<MPPlugin *> *)plugins {
return [self.mutablePlugins copy];
}
- (NSArray<MPPlugin *> *)importPlugins {
NSPredicate *filterPredicate = [NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
return ([evaluatedObject conformsToProtocol:@protocol(MPImportPlugin)]);
}];
return [self.mutablePlugins filteredArrayUsingPredicate:filterPredicate];
}
- (BOOL)installPluginAtURL:(NSURL *)url error:(NSError *__autoreleasing *)error {
if(![self _isValidPluginURL:url]) {
if(error) {
@@ -120,9 +115,25 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
}
- (void)disablePlugin:(MPPlugin *)plugin {
if(plugin.bundle.bundleIdentifier.length == 0) {
return;
}
NSArray<NSString *> *disabledPlugins = [NSUserDefaults.standardUserDefaults arrayForKey:kMPSettingsKeyDisabledPlugins];
if(NSNotFound == [disabledPlugins indexOfObject:plugin.bundle.bundleIdentifier]) {
disabledPlugins = [disabledPlugins arrayByAddingObject:plugin.bundle.bundleIdentifier];
[NSUserDefaults.standardUserDefaults setObject:disabledPlugins forKey:kMPSettingsKeyDisabledPlugins];
}
}
- (void)enablePlugin:(MPPlugin *)plugin {
if(plugin.bundle.bundleIdentifier.length == 0) {
return;
}
NSArray<NSString *> *disabledPlugins = [NSUserDefaults.standardUserDefaults arrayForKey:kMPSettingsKeyDisabledPlugins];
disabledPlugins = [disabledPlugins filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
return ![evaluatedObject isEqualToString:plugin.bundle.bundleIdentifier];
}]];
[NSUserDefaults.standardUserDefaults setValue:disabledPlugins forKey:kMPSettingsKeyDisabledPlugins];
}
@@ -139,14 +150,28 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
#pragma mark - Plugin Loading
- (void)loadPlugins {
[MPPluginRepository.defaultRepository fetchRepositoryDataCompletionHandler:^(NSArray<MPPluginRepositoryItem *> * _Nonnull availablePlugins) {
dispatch_async(dispatch_get_main_queue(), ^{
[self _loadPlugins:availablePlugins];
});
}];
if(MPPluginRepository.defaultRepository.isInitialized) {
[self _loadPlugins];
}
else {
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(_didUpdateAvailablePlugins:)
name:MPPluginRepositoryDidUpdateAvailablePluginsNotification
object:MPPluginRepository.defaultRepository];
}
}
- (void)_loadPlugins:(NSArray<MPPluginRepositoryItem *> *)availablePlugins {
- (void)_didUpdateAvailablePlugins:(NSNotification *)notification {
[NSNotificationCenter.defaultCenter removeObserver:self
name:MPPluginRepositoryDidUpdateAvailablePluginsNotification
object:MPPluginRepository.defaultRepository];
/* load plugins on the main thread! */
dispatch_async(dispatch_get_main_queue(), ^{
[self _loadPlugins];
});
}
- (void)_loadPlugins {
NSURL *appSupportDir = [NSApp applicationSupportDirectoryURL:YES];
NSError *error;
NSLog(@"Looking for external plugins at %@.", appSupportDir.path);
@@ -183,8 +208,13 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
continue;
}
if([self _isDisabledPluginBundle:pluginBundle]) {
[self _addPluginForBundle:pluginBundle error:NSLocalizedString(@"PLUGIN_ERROR_DISABLED_PLUGIN", "Error for a plugin that is disabled.")];
}
if(![self _isSignedPluginURL:pluginURL]) {
if(self.loadUnsecurePlugins) {
BOOL loadInsecurePlugins = [NSUserDefaults.standardUserDefaults boolForKey:kMPSettingsKeyLoadUnsecurePlugins];
if(loadInsecurePlugins) {
NSLog(@"Loading unsecure Plugin at %@.", pluginURL.path);
}
else {
@@ -200,12 +230,13 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
continue;
};
if([self _validateUniqueBundle:pluginBundle]) {
if(![self _isUniqueBundle:pluginBundle]) {
NSLog(@"Plugin %@ already loaded!", pluginBundle.bundleIdentifier);
continue;
}
if(![self _isCompatiblePluginBundle:pluginBundle avaiablePlugins:availablePlugins ]) {
if(![self _isCompatiblePluginBundle:pluginBundle error:&error]) {
NSLog(@"Plugin %@ is not compatible with host!", pluginBundle.bundleIdentifier);
[self _addPluginForBundle:pluginBundle error:NSLocalizedString(@"PLUGIN_ERROR_HOST_VERSION_NOT_SUPPORTED", "Plugin is not with this version of MacPass")];
continue;
}
@@ -259,19 +290,20 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
[self _addPlugin:plugin];
}
- (BOOL)_validateUniqueBundle:(NSBundle *)bundle {
return ![self pluginWithBundleIdentifier:bundle.bundleIdentifier];
- (BOOL)_isUniqueBundle:(NSBundle *)bundle {
return (nil == [self pluginWithBundleIdentifier:bundle.bundleIdentifier]);
}
- (BOOL)_isCompatiblePluginBundle:(NSBundle *)bundle avaiablePlugins:(NSArray<MPPluginRepositoryItem *> *)availablePlugins {
- (BOOL)_isCompatiblePluginBundle:(NSBundle *)bundle error:(NSError * __autoreleasing *)error {
MPPluginRepositoryItem *repoItem;
for(MPPluginRepositoryItem *item in availablePlugins) {
for(MPPluginRepositoryItem *item in MPPluginRepository.defaultRepository.availablePlugins) {
if([item.bundleIdentifier isEqualToString:bundle.bundleIdentifier]) {
repoItem = item;
}
}
MPPluginVersion *version = [MPPluginVersion versionWithVersionString:bundle.infoDictionary[@"CFBundleShortVersionString"]];
return [repoItem isPluginVersionCompatibleWithHost:version];
BOOL isCompatible = [repoItem isPluginVersionCompatibleWithHost:bundle.infoDictionary[@"CFBundleShortVersionString"]];
BOOL loadIncompatible = [NSUserDefaults.standardUserDefaults boolForKey:kMPSettingsKeyLoadIncompatiblePlugins];
return (loadIncompatible || isCompatible);
}
- (BOOL)_isValidPluginURL:(NSURL *)url {
@@ -325,6 +357,14 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
return NO;
}
- (BOOL)_isDisabledPluginBundle:(NSBundle *)bundle {
if(bundle.bundleIdentifier.length == 0) {
return YES; // disbable by default if nothing is known
}
NSArray *disabledPlugins = [NSUserDefaults.standardUserDefaults arrayForKey:kMPSettingsKeyDisabledPlugins];
return (NSNotFound != [disabledPlugins indexOfObject:bundle.bundleIdentifier]);
}
- (void)_addPlugin:(MPPlugin *)plugin {
[self.mutablePlugins addObject:plugin];
if([plugin conformsToProtocol:@protocol(MPEntryActionPlugin)]) {

View File

@@ -24,13 +24,20 @@ NS_ASSUME_NONNULL_BEGIN
@import Foundation;
FOUNDATION_EXTERN NSString *const MPPluginRepositoryDidUpdateAvailablePluginsNotification;
@class MPPluginRepositoryItem;
@interface MPPluginRepository : NSObject
@property (class, strong, readonly) MPPluginRepository *defaultRepository;
- (void)fetchRepositoryDataCompletionHandler:(void (^)(NSArray<MPPluginRepositoryItem *> *availablePlugins))completionHandler;
@property (readonly) BOOL isInitialized;
/*
this property is set asynchronously, to make sure, you receive valid data,
register to MPPluginRepositoryDidUpdateAvailablePlugsinNotification and access
availablePlugins after you received at least on notification
*/
@property (nonatomic, copy, readonly) NSArray<MPPluginRepositoryItem *> *availablePlugins;
@end

View File

@@ -24,12 +24,20 @@
#import "MPConstants.h"
#import "MPPluginRepositoryItem.h"
NSString *const MPPluginRepositoryDidUpdateAvailablePluginsNotification = @"com.hicknhack.macpass.MPPluginRepositoryDidInitializeAvailablePluginsNotification";
@interface MPPluginRepository ()
@property (nonatomic, copy) NSArray<MPPluginRepositoryItem *> *availablePlugins;
@property NSTimeInterval lastDataFetchTime;
@property BOOL isInitialized;
@end
@implementation MPPluginRepository
@synthesize availablePlugins = _availablePlugins;
+ (instancetype)defaultRepository {
static MPPluginRepository *instance;
static dispatch_once_t onceToken;
@@ -39,6 +47,36 @@
return instance;
}
- (instancetype)init {
self = [super init];
if(self) {
_isInitialized = NO;
[self fetchRepositoryDataCompletionHandler:^(NSArray<MPPluginRepositoryItem *> * _Nonnull availablePlugins) {
self.availablePlugins = availablePlugins;
self.isInitialized = YES;
}];
}
return self;
}
- (NSArray<MPPluginRepositoryItem *> *)availablePlugins {
/* update cache on every read if it's older than 5 minutes */
if((NSDate.timeIntervalSinceReferenceDate - self.lastDataFetchTime) > 60*5 ) {
NSLog(@"%@: updating available plugins cache.", self.className);
[self fetchRepositoryDataCompletionHandler:^(NSArray<MPPluginRepositoryItem *> * _Nonnull availablePlugins) {
self.availablePlugins = availablePlugins;
}];
}
return _availablePlugins;
}
- (void)setAvailablePlugins:(NSArray<MPPluginRepositoryItem *> *)availablePlugins {
@synchronized (self) {
_availablePlugins = [availablePlugins copy];
self.lastDataFetchTime = NSDate.timeIntervalSinceReferenceDate;
[NSNotificationCenter.defaultCenter postNotificationName:MPPluginRepositoryDidUpdateAvailablePluginsNotification object:self];
}
}
- (void)fetchRepositoryDataCompletionHandler:(void (^)(NSArray<MPPluginRepositoryItem *> * _Nonnull))completionHandler {
NSString *urlString = NSBundle.mainBundle.infoDictionary[MPBundlePluginRepositoryURLKey];

View File

@@ -11,7 +11,7 @@
#import "MPPluginHost.h"
#import "MPPluginRepository.h"
#import "MPPluginRepositoryItem.h"
#import "MPPluginVersion.h"
#import "MPPluginVersionComparator.h"
typedef NS_ENUM(NSUInteger, MPPluginTableColumn) {
@@ -60,17 +60,17 @@ typedef NS_ENUM(NSUInteger, MPPluginTableColumn) {
view.textField.stringValue = item.name;
}
else if(column == MPPluginTableColumnCurrentVersion) {
view.textField.stringValue = item.currentVersion.versionString;
view.textField.stringValue = item.currentVersion;
}
else if(column == MPPluginTableColumnStatus) {
MPPlugin *plugin = [MPPluginHost.sharedHost pluginWithBundleIdentifier:item.bundleIdentifier];
if(!plugin) {
switch([plugin.version compare:item.currentVersion]) {
switch([plugin.shortVersionString compare:item.currentVersion]) {
case NSOrderedSame:
view.textField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_BROWSER_LATEST_VERSION_INSTALLED", "Status for an up-to-date plugin in the plugin browser")];
break;
case NSOrderedAscending:
view.textField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_BROWSER_NEWER_VERSION_%@_AVAILABLE", "Status for an outdated plugin version in the plugin browser"), item.currentVersion.versionString];
view.textField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_BROWSER_NEWER_VERSION_%@_AVAILABLE", "Status for an outdated plugin version in the plugin browser"), item.currentVersion];
break;
case NSOrderedDescending:
view.textField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_BROWSER_UNKNOWN_PLUGIN_VERSION", "Status for an unkonw plugin version in the plugin browser")];
@@ -89,12 +89,8 @@ typedef NS_ENUM(NSUInteger, MPPluginTableColumn) {
}
- (void)_refreshRepository {
[MPPluginRepository.defaultRepository fetchRepositoryDataCompletionHandler:^(NSArray<MPPluginRepositoryItem *> * _Nonnull availablePlugins) {
dispatch_async(dispatch_get_main_queue(), ^{
self.repositoryItems = availablePlugins;
self.repositoryItems = MPPluginRepository.defaultRepository.availablePlugins;
[self.itemTable reloadData];
});
}];
}

View File

@@ -24,12 +24,12 @@
NS_ASSUME_NONNULL_BEGIN
@class MPPluginVersion;
@class MPPluginVersionComparator;
@interface MPPluginRepositoryItem : NSObject
@property (copy,readonly, nullable) NSString *name;
@property (copy,readonly, nullable) MPPluginVersion *currentVersion;
@property (copy,readonly, nullable) NSString *currentVersion;
@property (copy,readonly, nullable) NSString *descriptionText;
@property (copy,readonly, nullable) NSURL *sourceURL;
@property (copy,readonly, nullable) NSURL *downloadURL;
@@ -39,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (instancetype)pluginItemFromDictionary:(NSDictionary *)dict;
- (instancetype)initWithDictionary:(NSDictionary *)dict;
- (BOOL)isPluginVersionCompatibleWithHost:(MPPluginVersion *)pluginVersion;
- (BOOL)isPluginVersionCompatibleWithHost:(NSString *)pluginVersion;
@end

View File

@@ -22,7 +22,7 @@
#import "MPPluginRepositoryItem.h"
#import "MPPluginRepositoryItemVersionInfo.h"
#import "MPPluginVersion.h"
#import "MPPluginVersionComparator.h"
#import "MPPluginHost.h"
#import "NSError+Messages.h"
@@ -38,7 +38,7 @@ NSString *const MPPluginItemCompatibiltyKey = @"compatibilty";
@interface MPPluginRepositoryItem ()
@property (copy) NSString *name;
@property (copy) MPPluginVersion *currentVersion;
@property (copy) NSString *currentVersion;
@property (copy) NSString *descriptionText;
@property (copy) NSURL *sourceURL;
@property (copy) NSURL *downloadURL;
@@ -63,7 +63,7 @@ NSString *const MPPluginItemCompatibiltyKey = @"compatibilty";
self.descriptionText = dict[MPPluginItemDescriptionKey];
self.downloadURL = [NSURL URLWithString:dict[MPPluginItemDownloadURLKey]];
self.sourceURL = [NSURL URLWithString:dict[MPPluginItemSourceURLKey]];
self.currentVersion = [MPPluginVersion versionWithVersionString:dict[MPPluginItemCurrentVersionKey]];
self.currentVersion = dict[MPPluginItemCurrentVersionKey];
self.bundleIdentifier = dict[MPPluginItemBundleIdentifierKey];
[self _buildVersionInfos:dict[MPPluginItemCompatibiltyKey]];
@@ -76,29 +76,29 @@ NSString *const MPPluginItemCompatibiltyKey = @"compatibilty";
return (self.name.length > 0 && self.downloadURL);
}
- (BOOL)isPluginVersionCompatibleWithHost:(MPPluginVersion *)pluginVersion {
- (BOOL)isPluginVersionCompatibleWithHost:(NSString *)pluginVersion {
if(!pluginVersion) {
return NO;
}
MPPluginVersion *hostVersion = MPPluginHost.sharedHost.version;
if(!hostVersion) {
if(!MPPluginHost.sharedHost.version) {
return NO;
}
NSMutableArray<MPPluginRepositoryItemVersionInfo *> *matches = [[NSMutableArray alloc] init];
for(MPPluginRepositoryItemVersionInfo *info in self.compatibilty) {
if(NSOrderedSame == [info.version compare:pluginVersion]) {
if(NSOrderedSame == [MPPluginVersionComparator compareVersion:info.version toVersion:pluginVersion]) {
[matches addObject:info];
}
}
if(matches.count != 1) {
NSLog(@"No unique version match found.");
return NO;
}
MPPluginRepositoryItemVersionInfo *matchingInfo = matches.firstObject;
return [matchingInfo isCompatibleWithHostVersion:hostVersion];
return [matchingInfo isCompatibleWithHostVersion:MPPluginHost.sharedHost.version];
}
- (void)_buildVersionInfos:(NSArray<NSDictionary *>*)infos {

View File

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

View File

@@ -7,7 +7,7 @@
//
#import "MPPluginRepositoryItemVersionInfo.h"
#import "MPPluginVersion.h"
#import "MPPluginVersionComparator.h"
NSString *const MPPluginItemCompatibiltyVersionKey = @"pluginVersion";
NSString *const MPPluginItemCompatibiltyMinimumHostVersionKey = @"minimumHostVersion";
@@ -15,9 +15,9 @@ NSString *const MPPluginItemCompatibiltyMaxiumumHostVersionKey = @"maximumHostVe
@interface MPPluginRepositoryItemVersionInfo ()
@property (copy) MPPluginVersion *version;
@property (copy) MPPluginVersion *minimumHostVersion;
@property (copy) MPPluginVersion *maxiumHostVersion;
@property (copy) NSString *version;
@property (copy) NSString *minimumHostVersion;
@property (copy) NSString *maxiumHostVersion;
@end
@@ -30,51 +30,21 @@ NSString *const MPPluginItemCompatibiltyMaxiumumHostVersionKey = @"maximumHostVe
- (instancetype)initWithDict:(NSDictionary *)dict {
self = [super init];
if(self) {
NSString *versionString = dict[MPPluginItemCompatibiltyVersionKey];
if(!versionString) {
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;
}
}
self.version = dict[MPPluginItemCompatibiltyVersionKey];
self.minimumHostVersion = dict[MPPluginItemCompatibiltyMinimumHostVersionKey];
self.maxiumHostVersion = dict[MPPluginItemCompatibiltyMaxiumumHostVersionKey];
}
return self;
}
- (BOOL)isCompatibleWithHostVersion:(MPPluginVersion *)hostVersion {
if(NSOrderedDescending == [self.minimumHostVersion compare:hostVersion]) {
- (BOOL)isCompatibleWithHostVersion:(NSString *)hostVersion {
if(NSOrderedDescending == [MPPluginVersionComparator compareVersion:self.minimumHostVersion toVersion:hostVersion]) {
return NO;
}
if(!self.maxiumHostVersion) {
return YES;
}
return (NSOrderedAscending != [self.maxiumHostVersion compare:hostVersion]);
return (NSOrderedAscending != [MPPluginVersionComparator compareVersion:self.maxiumHostVersion toVersion:hostVersion]);
}

View File

@@ -42,12 +42,13 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
@interface MPPluginSettingsController () <NSTableViewDataSource, NSTableViewDelegate>
@property (weak) IBOutlet NSTableView *pluginTableView;
@property (weak) IBOutlet NSView *settingsView;
@property (strong) IBOutlet NSTableView *pluginTableView;
@property (strong) IBOutlet NSView *settingsView;
@property (strong) IBOutlet NSView *fallbackSettingsView;
@property (weak) IBOutlet NSTextField *fallbackDescriptionTextField;
@property (weak) IBOutlet NSButton *loadInsecurePlugsinCheckButton;
@property (weak) IBOutlet NSSegmentedControl *addRemovePluginsControl;
@property (strong) IBOutlet NSTextField *fallbackDescriptionTextField;
@property (strong) IBOutlet NSButton *loadInsecurePlugsinCheckButton;
@property (strong) IBOutlet NSSegmentedControl *addRemovePluginsControl;
@property (strong) IBOutlet NSButton *forceIncompatiblePluginsCheckButton;
@end
@@ -75,9 +76,13 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
[self.addRemovePluginsControl setEnabled:NO forSegment:MPRemovePluginSegment];
[self.fallbackSettingsView removeFromSuperview];
[self.loadInsecurePlugsinCheckButton bind:NSValueBinding
toObject:[NSUserDefaultsController sharedUserDefaultsController]
toObject:NSUserDefaultsController.sharedUserDefaultsController
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyLoadUnsecurePlugins]
options:nil];
[self.forceIncompatiblePluginsCheckButton bind:NSValueBinding
toObject:NSUserDefaultsController.sharedUserDefaultsController
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyLoadIncompatiblePlugins]
options:nil];
[self.pluginTableView registerForDraggedTypes:@[(NSString *)kUTTypeFileURL]];
}

View File

@@ -1,31 +0,0 @@
//
// 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

View File

@@ -1,122 +0,0 @@
//
// 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,30 @@
//
// 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 MPPluginVersionComparator : NSObject
typedef NS_ENUM(NSUInteger, MPVersionCharacterType ) {
kMPVersionCharacterTypeWildcard,
kMPVersionCharacterTypeSeparator,
kMPVersionCharacterTypeNumeric,
kMPVersionCharacterTypeString
};
+ (MPVersionCharacterType)typeOfCharacter:(NSString *)character;
+ (NSArray<NSString *> *)splitVersionString:(NSString *)versionString;
+ (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,167 @@
//
// MPPluginVersion.m
// MacPass
//
// Created by Michael Starke on 05.10.18.
// Copyright © 2018 HicknHack Software GmbH. All rights reserved.
//
#import "MPPluginVersionComparator.h"
@implementation MPPluginVersionComparator
+ (MPVersionCharacterType)typeOfCharacter:(NSString *)character {
if([character isEqualToString:@"."]) {
return kMPVersionCharacterTypeSeparator;
}
if([character isEqualToString:@"*"]) {
return kMPVersionCharacterTypeWildcard;
}
else if([NSCharacterSet.decimalDigitCharacterSet characterIsMember:[character characterAtIndex:0]]) {
return kMPVersionCharacterTypeNumeric;
}
else if([NSCharacterSet.whitespaceAndNewlineCharacterSet characterIsMember:[character characterAtIndex:0]]) {
return kMPVersionCharacterTypeSeparator;
}
else if([NSCharacterSet.punctuationCharacterSet characterIsMember:[character characterAtIndex:0]]) {
return kMPVersionCharacterTypeSeparator;
}
return kMPVersionCharacterTypeString;
}
+ (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB {
NSArray<NSString *>* partsA = [self splitVersionString:versionA];
NSArray<NSString *>* partsB = [self splitVersionString:versionB];
MPVersionCharacterType typeA;
MPVersionCharacterType typeB;
NSUInteger minPartsCount = MIN(partsA.count, partsB.count);
for(NSUInteger index = 0; index < minPartsCount; index++) {
NSString *partA = partsA[index];
NSString *partB = partsB[index];
typeA = [self typeOfCharacter:partA];
typeB = [self typeOfCharacter:partB];
if(typeA == typeB) {
if(typeA == kMPVersionCharacterTypeNumeric) {
NSInteger valueA = partA.integerValue;
NSInteger valueB = partB.integerValue;
if(valueA < valueB) {
return NSOrderedAscending;
}
else if (valueA > valueB) {
return NSOrderedDescending;
}
}
else if(typeA == kMPVersionCharacterTypeString) {
NSComparisonResult stringCompare = [partA compare:partB];
if(stringCompare != NSOrderedSame) {
return stringCompare;
}
}
}
else {
/* no wildcards, direct compare */
if(typeA != kMPVersionCharacterTypeWildcard && typeB != kMPVersionCharacterTypeWildcard) {
if(typeA != kMPVersionCharacterTypeString && typeB == kMPVersionCharacterTypeString) {
return NSOrderedDescending;
}
else if(typeA == kMPVersionCharacterTypeString && typeB != kMPVersionCharacterTypeString) {
return NSOrderedAscending;
}
else {
if(typeA == kMPVersionCharacterTypeNumeric) {
return NSOrderedDescending;
}
else {
return NSOrderedAscending;
}
}
}
/* we have at least one wildcards */
else {
/* one is separator, separator wins*/
if(typeA == kMPVersionCharacterTypeSeparator) {
return NSOrderedDescending;
}
else if(typeB == kMPVersionCharacterTypeSeparator) {
return NSOrderedAscending;
}
/* one is number or string, gets matched by wildcard */
}
}
}
if(partsA.count != partsB.count) {
NSArray *longerParts;
NSComparisonResult shorterResult;
NSComparisonResult longerResult;
MPVersionCharacterType lastShortType;
if(partsA.count > partsB.count) {
lastShortType = typeB;
longerParts = partsA;
shorterResult = NSOrderedAscending;
longerResult = NSOrderedDescending;
}
else {
lastShortType = typeA;
longerParts = partsB;
shorterResult = NSOrderedDescending;
longerResult = NSOrderedAscending;
}
/* check if wildcard was last part, then the rest does not matter */
if(lastShortType == kMPVersionCharacterTypeWildcard) {
return NSOrderedSame;
}
for(NSUInteger longerPartsIndex = minPartsCount; longerPartsIndex < longerParts.count; longerPartsIndex++) {
NSString *part = longerParts[longerPartsIndex];
MPVersionCharacterType type = [self typeOfCharacter:part];
/* overhangpart is string, the shorter wins */
if(type == kMPVersionCharacterTypeString) {
return shorterResult;
}
/* overhangpart is number, if not null, longer wins */
else if(type == kMPVersionCharacterTypeNumeric) {
if(part.integerValue != 0) {
return longerResult;
}
}
// versions are considered the same as long as 0, separators or wildcards follow
}
}
return NSOrderedSame;
}
+ (NSArray<NSString *> *)splitVersionString:(NSString *)versionString {
if(versionString.length == 0) {
return @[];
}
NSMutableArray *versionSegements = [[NSMutableArray alloc] init];
NSMutableString *currentSegment = [[versionString substringWithRange:NSMakeRange(0, 1)] mutableCopy];
MPVersionCharacterType oldType = [self typeOfCharacter:currentSegment];
for(NSUInteger characterIndex = 1; characterIndex < versionString.length; characterIndex++) {
NSString *character = [versionString substringWithRange:NSMakeRange(characterIndex, 1)];
MPVersionCharacterType newType = [self typeOfCharacter:character];
if(oldType != newType || newType == kMPVersionCharacterTypeSeparator) {
[versionSegements addObject:[currentSegment copy]];
[currentSegment setString:character];
}
else {
[currentSegment appendString:character];
}
oldType = newType;
}
[versionSegements addObject:[currentSegment copy]];
return [versionSegements copy];
}
@end

View File

@@ -80,6 +80,7 @@ APPKIT_EXTERN NSString *const kMPSettingsKeyUpdatePasswordOnTemplateEntries;
/* Plugins */
APPKIT_EXTERN NSString *const kMPSettingsKeyLoadUnsecurePlugins; // If set to YES this will load all plugins regardless of their codesignature status
APPKIT_EXTERN NSString *const kMPSettingsKeyDisabledPlugins; // NSArray of bundle identifiers of disabled plugins
APPKIT_EXTERN NSString *const kMPSettingsKeyLoadIncompatiblePlugins; // If set to YES incompatible plugins (no version info, marked as incompatible, etc) will be loaded regardless
typedef NS_ENUM(NSUInteger, MPFileChangeStrategy) {
MPFileChangeStrategyAsk,

View File

@@ -75,6 +75,7 @@ NSString *const kMPSettingsKeyDoubleClickTitleAction = @"Double
NSString *const kMPSettingsKeyUpdatePasswordOnTemplateEntries = @"UpdatePasswordOnTemplateEntries";
NSString *const kMPSettingsKeyLoadUnsecurePlugins = @"LoadUnsecurePlugins";
NSString *const kMPSettingsKeyLoadIncompatiblePlugins = @"LoadIncompatiblePlugins";
NSString *const kMPSettingsKeyDisabledPlugins = @"DisabledPlugins";
/* Deprecated */
@@ -147,7 +148,8 @@ NSString *const kMPDepricatedSettingsKeyLoadUnsecurePlugins = @"MP
kMPSettingsKeyDoubleClickTitleAction: @(MPDoubleClickTitleActionInspect),
kMPSettingsKeyLoadUnsecurePlugins: @NO,
kMPSettingsKeyUpdatePasswordOnTemplateEntries: @YES,
kMPSettingsKeyDisabledPlugins: @[]
kMPSettingsKeyDisabledPlugins: @[],
kMPSettingsKeyLoadIncompatiblePlugins: @NO
};
});
return standardDefaults;

View File

@@ -161,7 +161,7 @@
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="refresh:" target="-2" id="xld-yu-3Q9"/>
<action selector="refresh:" target="-2" id="kif-fN-nkM"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Pkh-la-7FU">

View File

@@ -1,150 +0,0 @@
//
// 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

View File

@@ -0,0 +1,84 @@
//
// MPTestPluginVersion.m
// MacPassTests
//
// Created by Michael Starke on 05.10.18.
// Copyright © 2018 HicknHack Software GmbH. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "MPPluginVersionComparator.h"
@interface MPTestPluginVersion : XCTestCase
@end
@implementation MPTestPluginVersion
- (void)testSegmentClasification {
XCTAssertEqual([MPPluginVersionComparator typeOfCharacter:@"1"], kMPVersionCharacterTypeNumeric);
XCTAssertEqual([MPPluginVersionComparator typeOfCharacter:@"9"], kMPVersionCharacterTypeNumeric);
XCTAssertEqual([MPPluginVersionComparator typeOfCharacter:@"*"], kMPVersionCharacterTypeWildcard);
XCTAssertEqual([MPPluginVersionComparator typeOfCharacter:@"a"], kMPVersionCharacterTypeString);
XCTAssertEqual([MPPluginVersionComparator typeOfCharacter:@"x"], kMPVersionCharacterTypeString);
XCTAssertEqual([MPPluginVersionComparator typeOfCharacter:@"Ñ"], kMPVersionCharacterTypeString);
XCTAssertEqual([MPPluginVersionComparator typeOfCharacter:@"."], kMPVersionCharacterTypeSeparator);
XCTAssertEqual([MPPluginVersionComparator typeOfCharacter:@"-"], kMPVersionCharacterTypeSeparator);
XCTAssertEqual([MPPluginVersionComparator typeOfCharacter:@":"], kMPVersionCharacterTypeSeparator);
XCTAssertEqual([MPPluginVersionComparator typeOfCharacter:@"!"], kMPVersionCharacterTypeSeparator);
}
- (void)testVersionSplitting {
NSArray *data = @[
@"10.1.99", @[@"10", @".", @"1", @".", @"99"],
@"0.152", @[@"0", @".", @"152"],
@"1.1.1beta", @[@"1", @".", @"1", @".", @"1", @"beta"],
@"beta2.0", @[@"beta", @"2", @".", @"0"],
@"*.*.1", @[@"*", @".", @"*", @".", @"1"],
@"1-*", @[@"1", @"-", @"*"],
@"1-1-1", @[@"1", @"-", @"1", @"-", @"1"]
];
for(NSUInteger index = 0; index < data.count; index += 2 ) {
NSString *versionString = data[index];
NSArray *versionParts = data[index+1];
XCTAssertEqualObjects([MPPluginVersionComparator splitVersionString:versionString], versionParts);
}
}
- (void)testVersionCompare {
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"" toVersion:@""]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"*" toVersion:@"*"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"1.0.1" toVersion:@"*"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"*" toVersion:@"1.0.1"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"1.*" toVersion:@"1.*"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"1.1.*" toVersion:@"1.1.*"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"1.1.1" toVersion:@"1.1.1"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"1.0.1" toVersion:@"*"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"0.10.*" toVersion:@"0.10.1"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"10.*.1" toVersion:@"10.99.*"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"0.9.89" toVersion:@"0.9.89"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"1.*" toVersion:@"1.*.1"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"1.*.2" toVersion:@"1.*"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"1.0" toVersion:@"1."]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"1.0" toVersion:@"1.0.0"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"1.0" toVersion:@"1.0.0.0.0.0.0.0"]);
XCTAssertEqual(NSOrderedSame, [MPPluginVersionComparator compareVersion:@"1.0.*" toVersion:@"1.0"]);
XCTAssertEqual(NSOrderedAscending, [MPPluginVersionComparator compareVersion:@"0.0.1" toVersion:@"0.0.2"]);
XCTAssertEqual(NSOrderedAscending, [MPPluginVersionComparator compareVersion:@"0.0.1b" toVersion:@"0.0.1"]);
XCTAssertEqual(NSOrderedAscending, [MPPluginVersionComparator compareVersion:@"1.10.10" toVersion:@"1.12.10"]);
XCTAssertEqual(NSOrderedAscending, [MPPluginVersionComparator compareVersion:@"20.0.1" toVersion:@"20.1.0"]);
XCTAssertEqual(NSOrderedAscending, [MPPluginVersionComparator compareVersion:@"1.1.1" toVersion:@"2.*"]);
XCTAssertEqual(NSOrderedAscending, [MPPluginVersionComparator compareVersion:@"1.*" toVersion:@"2.0.*"]);
XCTAssertEqual(NSOrderedDescending, [MPPluginVersionComparator compareVersion:@"2.1.1" toVersion:@"2.0.0"]);
XCTAssertEqual(NSOrderedDescending, [MPPluginVersionComparator compareVersion:@"2.0.0" toVersion:@"2.0.0b"]);
XCTAssertEqual(NSOrderedDescending, [MPPluginVersionComparator compareVersion:@"2.0.0" toVersion:@"2.0.0.0.0.beta"]);
XCTAssertEqual(NSOrderedDescending, [MPPluginVersionComparator compareVersion:@"0.1.1" toVersion:@"0.1.0"]);
XCTAssertEqual(NSOrderedDescending, [MPPluginVersionComparator compareVersion:@"1.2.*" toVersion:@"1.1.*"]);
XCTAssertEqual(NSOrderedDescending, [MPPluginVersionComparator compareVersion:@"2.*" toVersion:@"1.*"]);
}
@end