Преглед изворни кода

Set ClientPlatform in library, non-overridable

This allows us to tightly control the value of ClientPlatform, for easier parsing and stats.

Also added some jailbroken-ness detection code, to help build the ClientPlatform value.
Adam Pritchard пре 9 година
родитељ
комит
8253a58f74

+ 16 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel.xcodeproj/project.pbxproj

@@ -18,6 +18,8 @@
 		6685BDD41E2EBB1000F0E414 /* GoPsi.objc.h in Headers */ = {isa = PBXBuildFile; fileRef = 6685BDD21E2EBB1000F0E414 /* GoPsi.objc.h */; };
 		6685BDD51E2EBB1000F0E414 /* Universe.objc.h in Headers */ = {isa = PBXBuildFile; fileRef = 6685BDD31E2EBB1000F0E414 /* Universe.objc.h */; };
 		6685BDD91E300AC200F0E414 /* strip-frameworks.sh in Resources */ = {isa = PBXBuildFile; fileRef = 6685BDD81E300AC200F0E414 /* strip-frameworks.sh */; };
+		66BAD3351E525FBC00CD06DE /* JailbreakCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 66BAD3331E525FBC00CD06DE /* JailbreakCheck.h */; };
+		66BAD3361E525FBC00CD06DE /* JailbreakCheck.m in Sources */ = {isa = PBXBuildFile; fileRef = 66BAD3341E525FBC00CD06DE /* JailbreakCheck.m */; };
 		66BDB02A1DA6BFCC0079384C /* PsiphonTunnel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66BDB0201DA6BFCC0079384C /* PsiphonTunnel.framework */; };
 		66BDB02F1DA6BFCC0079384C /* PsiphonTunnelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 66BDB02E1DA6BFCC0079384C /* PsiphonTunnelTests.m */; };
 		66BDB0311DA6BFCC0079384C /* PsiphonTunnel.h in Headers */ = {isa = PBXBuildFile; fileRef = 66BDB0231DA6BFCC0079384C /* PsiphonTunnel.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -74,6 +76,8 @@
 		6685BDD21E2EBB1000F0E414 /* GoPsi.objc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GoPsi.objc.h; path = PsiphonTunnel/Psi.framework/Versions/A/Headers/GoPsi.objc.h; sourceTree = "<group>"; };
 		6685BDD31E2EBB1000F0E414 /* Universe.objc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Universe.objc.h; path = PsiphonTunnel/Psi.framework/Versions/A/Headers/Universe.objc.h; sourceTree = "<group>"; };
 		6685BDD81E300AC200F0E414 /* strip-frameworks.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = "strip-frameworks.sh"; path = "scripts/strip-frameworks.sh"; sourceTree = "<group>"; };
+		66BAD3331E525FBC00CD06DE /* JailbreakCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JailbreakCheck.h; sourceTree = "<group>"; };
+		66BAD3341E525FBC00CD06DE /* JailbreakCheck.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JailbreakCheck.m; sourceTree = "<group>"; };
 		66BDB0201DA6BFCC0079384C /* PsiphonTunnel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PsiphonTunnel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		66BDB0231DA6BFCC0079384C /* PsiphonTunnel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PsiphonTunnel.h; sourceTree = "<group>"; };
 		66BDB0241DA6BFCC0079384C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -143,6 +147,15 @@
 			name = Psi;
 			sourceTree = "<group>";
 		};
+		66BAD3321E525FBC00CD06DE /* JailbreakCheck */ = {
+			isa = PBXGroup;
+			children = (
+				66BAD3331E525FBC00CD06DE /* JailbreakCheck.h */,
+				66BAD3341E525FBC00CD06DE /* JailbreakCheck.m */,
+			);
+			path = JailbreakCheck;
+			sourceTree = "<group>";
+		};
 		66BDB0161DA6BFCC0079384C = {
 			isa = PBXGroup;
 			children = (
@@ -166,6 +179,7 @@
 		66BDB0221DA6BFCC0079384C /* PsiphonTunnel */ = {
 			isa = PBXGroup;
 			children = (
+				66BAD3321E525FBC00CD06DE /* JailbreakCheck */,
 				662659241DD270E900872F6C /* Reachability */,
 				66BDB04A1DC26CCC0079384C /* json-framework */,
 				66BDB0231DA6BFCC0079384C /* PsiphonTunnel.h */,
@@ -222,6 +236,7 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				66BAD3351E525FBC00CD06DE /* JailbreakCheck.h in Headers */,
 				6685BDCB1E2E882800F0E414 /* ref.h in Headers */,
 				4E89F7FF1E2ED3CE00005F4C /* LookupIPv6.h in Headers */,
 				662659271DD270E900872F6C /* Reachability.h in Headers */,
@@ -349,6 +364,7 @@
 				66BDB0661DC26CCC0079384C /* SBJson4StreamWriterState.m in Sources */,
 				66BDB05C1DC26CCC0079384C /* SBJson4Parser.m in Sources */,
 				4E89F7FE1E2ED3CE00005F4C /* LookupIPv6.c in Sources */,
+				66BAD3361E525FBC00CD06DE /* JailbreakCheck.m in Sources */,
 				66BDB0681DC26CCC0079384C /* SBJson4Writer.m in Sources */,
 				66BDB0621DC26CCC0079384C /* SBJson4StreamTokeniser.m in Sources */,
 				66BDB0441DA6C7DD0079384C /* PsiphonTunnel.m in Sources */,

+ 25 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/JailbreakCheck/JailbreakCheck.h

@@ -0,0 +1,25 @@
+//
+//  JailbreakCheck.h
+//  JailbreakCheck
+//
+
+/*
+ * Copyright (c) 2017, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+BOOL isDeviceJailbroken();

+ 125 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/JailbreakCheck/JailbreakCheck.m

@@ -0,0 +1,125 @@
+// Adapted from https://github.com/olxios/JailbreakCheck
+/*
+ MIT License
+
+ Copyright (c) 2016 olxios
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+
+#import <Foundation/Foundation.h>
+#import "UIKit/UIKit.h"
+#import <sys/stat.h>
+
+
+BOOL checkReadWritePermissions()
+{
+    if([[UIApplication sharedApplication] canOpenURL:
+        [NSURL URLWithString:@"cydia://package/com.com.com"]])
+    {
+        return TRUE;
+    }
+
+    NSError *error;
+    NSString *stringToBeWritten = @"0";
+    [stringToBeWritten writeToFile:@"/private/jailbreak.test"
+                        atomically:YES
+                          encoding:NSUTF8StringEncoding error:&error];
+    if (error == nil)
+    {
+        return TRUE;
+    }
+    
+    return FALSE;
+}
+
+BOOL checkJailbreakSymLink(NSString *checkPath)
+{
+    struct stat s;
+
+    if (lstat([checkPath UTF8String], &s) == 0)
+    {
+        if (S_ISLNK(s.st_mode) == 1)
+        {
+            return TRUE;
+        }
+    }
+    
+    return FALSE;
+}
+
+BOOL checkJailbreakSymlinks()
+{
+    NSArray *linksChecks = @[@"/Applications",
+                             @"/usr/libexec",
+                             @"/usr/share",
+                             @"/Library/Wallpaper",
+                             @"/usr/include"];
+    
+    for (NSString *checkPath in linksChecks)
+    {
+        if (checkJailbreakSymLink(checkPath)) {
+            return TRUE;
+        }
+    }
+    
+    return FALSE;
+}
+
+BOOL checkJailbreakFile(NSString *checkPath)
+{
+    struct stat s;
+
+    if (stat([checkPath UTF8String], &s) == 0)
+    {
+        return TRUE;
+    }
+    
+    return FALSE;
+}
+
+BOOL checkJailbreakFiles()
+{
+    NSArray *fileChecks = @[@"/bin/bash",
+                            @"/etc/apt",
+                            @"/usr/sbin/sshd",
+                            @"/Library/MobileSubstrate/MobileSubstrate.dylib",
+                            @"/Applications/Cydia.app",
+                            @"/bin/sh",
+                            @"/var/cache/apt",
+                            @"/var/tmp/cydia.log"];
+    
+    for (NSString *checkPath in fileChecks)
+    {
+        if (checkJailbreakFile(checkPath)) {
+            return TRUE;
+        }
+    }
+    
+    return FALSE;
+}
+
+BOOL isDeviceJailbroken()
+{
+    return
+        checkJailbreakSymlinks()
+        || checkJailbreakFiles()
+        || checkReadWritePermissions();
+}

+ 0 - 1
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/PsiphonTunnel.h

@@ -61,7 +61,6 @@ FOUNDATION_EXPORT const unsigned char PsiphonTunnelVersionString[];
  - `DataStoreDirectory`: If not set, the library will use a sane location. Override if the client wants to restrict where operational data is kept. If overridden, the directory must already exist and be writable.
  - `RemoteServerListDownloadFilename`: If not set, the library will use a sane location. Override if the client wants to restrict where operational data is kept.
  - `ObfuscatedServerListDownloadDirectory`: If not set, the library will use a sane location. Override if the client wants to restrict where operational data is kept. If overridden, the directory must already exist and be writable.
- - `ClientPlatform`: Should not be set by most library consumers.
  - `UpstreamProxyUrl`
  - `EmitDiagnosticNotices`
  - `EgressRegion`

+ 22 - 12
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/PsiphonTunnel.m

@@ -23,6 +23,7 @@
 #import "Psi-meta.h"
 #import "PsiphonTunnel.h"
 #import "json-framework/SBJson4.h"
+#import "JailbreakCheck/JailbreakCheck.h"
 
 
 @interface PsiphonTunnel () <GoPsiPsiphonProvider>
@@ -284,6 +285,27 @@
     // Fill in the rest of the values.
     //
     
+    // Ensure the elements of the ClientPlatform do not contain underscores, as that's what we use to separate the elements.
+    // Like "iOS"
+    NSString *systemName = [[[UIDevice currentDevice] systemName] stringByReplacingOccurrencesOfString:@"_" withString:@"-"];
+    // Like "10.2.1"
+    NSString *systemVersion = [[[UIDevice currentDevice]systemVersion] stringByReplacingOccurrencesOfString:@"_" withString:@"-"];
+    // "unjailbroken"/"jailbroken"
+    NSString *jailbroken = @"unjailbroken";
+    if (isDeviceJailbroken()) {
+        jailbroken = @"jailbroken";
+    }
+    // Like "com.psiphon3.browser"
+    NSString *bundleIdentifier = [[[NSBundle mainBundle] bundleIdentifier] stringByReplacingOccurrencesOfString:@"_" withString:@"-"];
+    
+    NSString *clientPlatform = [NSString stringWithFormat:@"%@_%@_%@_%@",
+                                systemName,
+                                systemVersion,
+                                jailbroken,
+                                bundleIdentifier];
+    
+    config[@"ClientPlatform"] = clientPlatform;
+        
     config[@"EmitBytesTransferred"] = [NSNumber numberWithBool:TRUE];
 
     config[@"DeviceRegion"] = [PsiphonTunnel getDeviceRegion];
@@ -301,18 +323,6 @@
     }
     config[@"TrustedCACertificatesFilename"] = bundledTrustedCAPath;
     
-    //
-    // Many other fields must *only* be modified by official Psiphon clients.
-    // Some of them require default values.
-    //
-    
-    if (config[@"ClientPlatform"] == nil) {
-        config[@"ClientPlatform"] = @"iOS-Library";
-    }
-    else {
-        [self logMessage:[NSString stringWithFormat: @"ClientPlatform overridden from 'iOS-Library' to '%@'", config[@"ClientPlatform"]]];
-    }
-
     NSString *finalConfigStr = [[[SBJson4Writer alloc] init] stringWithObject:config];
     
     if (finalConfigStr == nil) {