diff --git a/V2RayX/AppDelegate.m b/V2RayX/AppDelegate.m
index 1a33cd7..ad7d03c 100644
--- a/V2RayX/AppDelegate.m
+++ b/V2RayX/AppDelegate.m
@@ -566,7 +566,7 @@ - (IBAction)updateSubscriptions:(id)sender {
_subsOutbounds = [[NSMutableArray alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
for (NSString* link in self.subscriptions) {
- NSDictionary* r = [ConfigImporter importFromSubscriptionOfV2RayN:link];
+ NSDictionary* r = [ConfigImporter importFromHTTPSubscription:link];
if (r) {
for (ServerProfile* p in r[@"vmess"]) {
[self.subsOutbounds addObject:[p outboundProfile]];
diff --git a/V2RayX/ConfigImporter.h b/V2RayX/ConfigImporter.h
index df9cde7..fa6910e 100644
--- a/V2RayX/ConfigImporter.h
+++ b/V2RayX/ConfigImporter.h
@@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSMutableDictionary*)ssOutboundFromSSLink:(NSString*)link;
+ (NSMutableDictionary*)ssOutboundFromSSConfig:(NSDictionary*)jsonObject;
+ (ServerProfile*)importFromVmessOfV2RayN:(NSString*)vmessStr;
-+ (NSMutableDictionary*)importFromSubscriptionOfV2RayN:(NSString*)httpLink;
++ (NSMutableDictionary*)importFromHTTPSubscription:(NSString*)httpLink;
+ (NSMutableDictionary*)importFromStandardConfigFiles:(NSArray*)files;
+ (NSMutableDictionary*)validateRuleSet:(NSMutableDictionary*)set;
+ (NSMutableDictionary* _Nonnull)importFromSubscriptionOfSSD: (NSString* _Nonnull)ssdLink;
diff --git a/V2RayX/ConfigImporter.m b/V2RayX/ConfigImporter.m
index 91b2de3..1cf7115 100644
--- a/V2RayX/ConfigImporter.m
+++ b/V2RayX/ConfigImporter.m
@@ -9,39 +9,62 @@
@implementation ConfigImporter
-+ (NSString*)decodeBase64String:(NSString*)encoded {
++ (NSString* _Nonnull)decodeBase64String:(NSString*)encoded {
+ if (!encoded || ![encoded isKindOfClass:[NSString class]] || encoded.length == 0) {
+ return @"";
+ }
NSMutableString* fixed = [encoded mutableCopy];
NSInteger numAdd = encoded.length % 4;
for (int i = 0; i < numAdd; i += 1) {
[fixed appendString:@"="];
}
- NSData* decodedData = [[NSData alloc] initWithBase64EncodedString:fixed options:NSDataBase64DecodingIgnoreUnknownCharacters];
- return [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
+ @try {
+ NSData* decodedData = [[NSData alloc] initWithBase64EncodedString:fixed options:NSDataBase64DecodingIgnoreUnknownCharacters];
+ NSString* decodedString = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
+ assert(decodedString != nil);
+ return decodedString;
+ } @catch (NSException *exception) {
+ return @"";
+ }
}
+ (NSDictionary*)parseLegacySSLink:(NSString*)link {
//http://shadowsocks.org/en/config/quick-guide.html
@try {
NSString* encoded = [[link stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] substringFromIndex:5];
- NSString* encodedRemoveTag = [encoded componentsSeparatedByString:@"#"][0];
+ NSArray* hashTagSeperatedParts = [encoded componentsSeparatedByString:@"#"];
+ NSString* encodedRemoveTag = hashTagSeperatedParts[0];
NSData* decodedData = [[NSData alloc] initWithBase64EncodedString:encodedRemoveTag options:0];
NSString* decoded = [[NSString alloc] initWithData: decodedData
encoding:NSUTF8StringEncoding];
NSArray* parts = [decoded componentsSeparatedByString:@"@"];
- NSArray* server_port = [parts[1] componentsSeparatedByString:@":"];
- NSMutableArray* method_password = [[parts[0] componentsSeparatedByString:@":"] mutableCopy];
- NSString* method = method_password[0];
- [method_password removeObjectAtIndex:0];
- return @{
- @"server":server_port[0],
- @"server_port":server_port[1],
- @"password": [method_password componentsJoinedByString:@":"],
- @"method":method};
+ NSArray* addressAndPort = [parts[1] componentsSeparatedByString:@":"];
+ NSMutableArray* methodAndPassword = [[parts[0] componentsSeparatedByString:@":"] mutableCopy];
+ NSString* method = methodAndPassword[0];
+ [methodAndPassword removeObjectAtIndex:0];
+
+ NSNumberFormatter* f = [[NSNumberFormatter alloc] init];
+ f.numberStyle = NSNumberFormatterDecimalStyle;
+ NSNumber *port = [f numberFromString:addressAndPort[1]];
+
+ if (hashTagSeperatedParts.count == 1) {
+ return @{
+ @"server":addressAndPort[0],
+ @"server_port":port,
+ @"password": [methodAndPassword componentsJoinedByString:@":"],
+ @"method":method};
+ } else {
+ return @{
+ @"server":addressAndPort[0],
+ @"server_port":port,
+ @"password": [methodAndPassword componentsJoinedByString:@":"],
+ @"method":method,
+ @"tag":hashTagSeperatedParts[1]
+ };
+ }
} @catch (NSException *exception) {
return nil;
- } @finally {
- ;
}
}
@@ -70,7 +93,6 @@ + (NSDictionary*)parseStandardSSLink:(NSString*)link {
if (!port) {
return nil;
}
-
return @{
@"server":hostInfo[0],
@"server_port":port,
@@ -80,12 +102,10 @@ + (NSDictionary*)parseStandardSSLink:(NSString*)link {
};
} @catch (NSException *exception) {
return nil;
- } @finally {
- ;
}
}
-+ (NSMutableDictionary*)ssOutboundFromSSLink:(NSString*)link {
++ (NSMutableDictionary* )ssOutboundFromSSLink:(NSString*)link {
NSDictionary* parsed = [ConfigImporter parseStandardSSLink:link];
if (parsed) {
return [ConfigImporter ssOutboundFromSSConfig:parsed];
@@ -257,7 +277,7 @@ + (NSMutableDictionary*)importFromStandardConfigFiles:(NSArray*)files {
return result;
}
-+ (NSMutableDictionary*)importFromSubscriptionOfV2RayN: (NSString*)httpLink {
++ (NSMutableDictionary*)importFromHTTPSubscription: (NSString*)httpLink {
// https://blog.csdn.net/yi_zz32/article/details/48769487
NSMutableDictionary* result = [@{@"vmess": @[], @"other": @[]} mutableDeepCopy];
if (![@"http" isEqualToString:[httpLink substringToIndex:4]]) {
@@ -286,6 +306,8 @@ + (NSMutableDictionary*)importFromSubscriptionOfV2RayN: (NSString*)httpLink {
[result[@"other"] addObject:outbound];
continue;
}
+ NSMutableDictionary* ssdResults = [ConfigImporter importFromSubscriptionOfSSD:linkStr];
+ [result[@"other"] addObjectsFromArray:ssdResults[@"other"]];
}
}
return result;
diff --git a/V2RayX/ConfigWindowController.m b/V2RayX/ConfigWindowController.m
index b9fa030..0057771 100644
--- a/V2RayX/ConfigWindowController.m
+++ b/V2RayX/ConfigWindowController.m
@@ -336,23 +336,27 @@ - (void)presentImportResultOfVmessCount:(NSInteger)vmessCount otherCount:(NSInte
}
- (IBAction)importFromMiscLinks:(id)sender {
- [self askInputWithPrompt:@"V2RayX will try importing vmess:// and http(s):// links from v2rayN ." handler:^(NSString *inputStr) {
+ [self askInputWithPrompt:@"V2RayX will try importing ssd://, vmess:// and http(s):// links from v2rayN and SSD." handler:^(NSString *inputStr) {
if ([inputStr length] != 0) {
- ServerProfile* p = [ConfigImporter importFromVmessOfV2RayN:inputStr];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
+ ServerProfile* p = [ConfigImporter importFromVmessOfV2RayN:inputStr];
NSInteger vmessCount = 0;
NSInteger otherCount = 0;
if (p) {
[self.profiles addObject:p];
vmessCount = 1;
- } else {
- NSMutableDictionary* p2 = [ConfigImporter importFromSubscriptionOfV2RayN:inputStr];
- if (p2) {
- [self.profiles addObjectsFromArray:p2[@"vmess"]];
- [self.outbounds addObjectsFromArray:p2[@"other"]];
- vmessCount = [p2[@"vmess"] count];
- otherCount = [p2[@"other"] count];
- }
+ }
+ NSDictionary* ssdResult = [ConfigImporter importFromSubscriptionOfSSD:inputStr];
+ for (NSDictionary* d in ssdResult[@"other"]) {
+ [self.outbounds addObject:[d mutableDeepCopy]];
+ otherCount += 1;
+ }
+ NSMutableDictionary* p2 = [ConfigImporter importFromHTTPSubscription:inputStr];
+ if (p2) {
+ [self.profiles addObjectsFromArray:p2[@"vmess"]];
+ [self.outbounds addObjectsFromArray:p2[@"other"]];
+ vmessCount += [p2[@"vmess"] count];
+ otherCount += [p2[@"other"] count];
}
[self presentImportResultOfVmessCount:vmessCount otherCount:otherCount ruleSetCount:0];
});
diff --git a/V2RayX/Info.plist b/V2RayX/Info.plist
index d1f562f..dd3929d 100644
--- a/V2RayX/Info.plist
+++ b/V2RayX/Info.plist
@@ -21,7 +21,7 @@
CFBundleSignature
????
CFBundleVersion
- 1142
+ 1235
LSMinimumSystemVersion
$(MACOSX_DEPLOYMENT_TARGET)
LSUIElement