Просмотр исходного кода

Additional structure for clientVerification; refactor client_platform normalization

Rod Hynes 9 лет назад
Родитель
Сommit
bcd8096cf8
3 измененных файлов с 78 добавлено и 27 удалено
  1. 41 4
      psiphon/server/api.go
  2. 10 23
      psiphon/server/psinet/psinet.go
  3. 27 0
      psiphon/server/safetyNet.go

+ 41 - 4
psiphon/server/api.go

@@ -33,7 +33,12 @@ import (
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
 )
 )
 
 
-const MAX_API_PARAMS_SIZE = 256 * 1024 // 256KB
+const (
+	MAX_API_PARAMS_SIZE = 256 * 1024 // 256KB
+
+	CLIENT_PLATFORM_ANDROID = "Android"
+	CLIENT_PLATFORM_WINDOWS = "Windows"
+)
 
 
 type requestJSONObject map[string]interface{}
 type requestJSONObject map[string]interface{}
 
 
@@ -123,10 +128,10 @@ func handshakeAPIRequestHandler(
 	// Note: no guarantee that PsinetDatabase won't reload between calls
 	// Note: no guarantee that PsinetDatabase won't reload between calls
 
 
 	handshakeResponse.Homepages = support.PsinetDatabase.GetHomepages(
 	handshakeResponse.Homepages = support.PsinetDatabase.GetHomepages(
-		sponsorID, clientRegion, clientPlatform)
+		sponsorID, clientRegion, isMobileClientPlatform(clientPlatform))
 
 
 	handshakeResponse.UpgradeClientVersion = support.PsinetDatabase.GetUpgradeClientVersion(
 	handshakeResponse.UpgradeClientVersion = support.PsinetDatabase.GetUpgradeClientVersion(
-		clientVersion, clientPlatform)
+		clientVersion, normalizeClientPlatform(clientPlatform))
 
 
 	handshakeResponse.HttpsRequestRegexes = support.PsinetDatabase.GetHttpsRequestRegexes(
 	handshakeResponse.HttpsRequestRegexes = support.PsinetDatabase.GetHttpsRequestRegexes(
 		sponsorID)
 		sponsorID)
@@ -330,7 +335,23 @@ func clientVerificationAPIRequestHandler(
 		return nil, psiphon.ContextError(errors.New("invalid params"))
 		return nil, psiphon.ContextError(errors.New("invalid params"))
 	}
 	}
 
 
-	// TODO: implement
+	// Ignoring error as params are validated
+	clientPlatform, _ := getStringRequestParam(params, "client_platform")
+
+	verificationData, err := getJSONObjectRequestParam(params, "verificationData")
+	if err != nil {
+		return nil, psiphon.ContextError(err)
+	}
+
+	var verified bool
+	switch normalizeClientPlatform(clientPlatform) {
+	case CLIENT_PLATFORM_ANDROID:
+		verified = verifySafetyNetPayload(verificationData)
+	}
+
+	if verified {
+		// TODO: change throttling treatment
+	}
 
 
 	return make([]byte, 0), nil
 	return make([]byte, 0), nil
 }
 }
@@ -548,6 +569,22 @@ func getMapStringInt64RequestParam(params requestJSONObject, name string) (map[s
 	return result, nil
 	return result, nil
 }
 }
 
 
+// Normalize reported client platform. Android clients, for example, report
+// OS version, rooted status, and Google Play build status in the clientPlatform
+// string along with "Android".
+func normalizeClientPlatform(clientPlatform string) string {
+
+	if strings.Contains(strings.ToLower(clientPlatform), strings.ToLower(CLIENT_PLATFORM_ANDROID)) {
+		return CLIENT_PLATFORM_ANDROID
+	}
+
+	return CLIENT_PLATFORM_WINDOWS
+}
+
+func isMobileClientPlatform(clientPlatform string) bool {
+	return normalizeClientPlatform(clientPlatform) == CLIENT_PLATFORM_ANDROID
+}
+
 // Input validators follow the legacy validations rules in psi_web.
 // Input validators follow the legacy validations rules in psi_web.
 
 
 func isServerSecret(support *SupportServices, value string) bool {
 func isServerSecret(support *SupportServices, value string) bool {

+ 10 - 23
psiphon/server/psinet/psinet.go

@@ -38,9 +38,6 @@ import (
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
 )
 )
 
 
-var CLIENT_PLATFORM_ANDROID string = "Android"
-var CLIENT_PLATFORM_WINDOWS string = "Windows"
-
 // Database serves Psiphon API data requests. It's safe for
 // Database serves Psiphon API data requests. It's safe for
 // concurrent usage. The Reload function supports hot reloading
 // concurrent usage. The Reload function supports hot reloading
 // of Psiphon network data while the server is running.
 // of Psiphon network data while the server is running.
@@ -156,7 +153,7 @@ func (db *Database) Reload(filename string) error {
 
 
 	configJSON, err := ioutil.ReadFile(filename)
 	configJSON, err := ioutil.ReadFile(filename)
 	if err != nil {
 	if err != nil {
-		return err
+		return psiphon.ContextError(err)
 	}
 	}
 
 
 	// Unmarshal first validates the provided JSON and then
 	// Unmarshal first validates the provided JSON and then
@@ -164,12 +161,12 @@ func (db *Database) Reload(filename string) error {
 	// persists if the new JSON is malformed.
 	// persists if the new JSON is malformed.
 	err = json.Unmarshal(configJSON, &db)
 	err = json.Unmarshal(configJSON, &db)
 
 
-	return err
+	return psiphon.ContextError(err)
 }
 }
 
 
 // GetHomepages returns a list of  home pages for the specified sponsor,
 // GetHomepages returns a list of  home pages for the specified sponsor,
 // region, and platform.
 // region, and platform.
-func (db *Database) GetHomepages(sponsorID, clientRegion, clientPlatform string) []string {
+func (db *Database) GetHomepages(sponsorID, clientRegion string, isMobilePlatform bool) []string {
 	db.RLock()
 	db.RLock()
 	defer db.RUnlock()
 	defer db.RUnlock()
 
 
@@ -183,7 +180,7 @@ func (db *Database) GetHomepages(sponsorID, clientRegion, clientPlatform string)
 
 
 	homePages := sponsor.HomePages
 	homePages := sponsor.HomePages
 
 
-	if getClientPlatform(clientPlatform) == CLIENT_PLATFORM_ANDROID {
+	if isMobilePlatform {
 		if sponsor.MobileHomePages != nil {
 		if sponsor.MobileHomePages != nil {
 			homePages = sponsor.MobileHomePages
 			homePages = sponsor.MobileHomePages
 		}
 		}
@@ -213,20 +210,22 @@ func (db *Database) GetHomepages(sponsorID, clientRegion, clientPlatform string)
 
 
 // GetUpgradeClientVersion returns a new client version when an upgrade is
 // GetUpgradeClientVersion returns a new client version when an upgrade is
 // indicated for the specified client current version. The result is "" when
 // indicated for the specified client current version. The result is "" when
-// no upgrade is available.
+// no upgrade is available. Caller should normalize clientPlatform.
 func (db *Database) GetUpgradeClientVersion(clientVersion, clientPlatform string) string {
 func (db *Database) GetUpgradeClientVersion(clientVersion, clientPlatform string) string {
 	db.RLock()
 	db.RLock()
 	defer db.RUnlock()
 	defer db.RUnlock()
 
 
 	// Check lastest version number against client version number
 	// Check lastest version number against client version number
-	platform := getClientPlatform(clientPlatform)
 
 
-	// If no versions exist for this platform
-	clientVersions, ok := db.Versions[platform]
+	clientVersions, ok := db.Versions[clientPlatform]
 	if !ok {
 	if !ok {
 		return ""
 		return ""
 	}
 	}
 
 
+	if len(clientVersions) == 0 {
+		return ""
+	}
+
 	// NOTE: Assumes versions list is in ascending version order
 	// NOTE: Assumes versions list is in ascending version order
 	lastVersion := clientVersions[len(clientVersions)-1].Version
 	lastVersion := clientVersions[len(clientVersions)-1].Version
 
 
@@ -525,15 +524,3 @@ func parseSshKeyString(sshKeyString string) (keyType string, key string) {
 
 
 	return sshKeyArr[0], sshKeyArr[1]
 	return sshKeyArr[0], sshKeyArr[1]
 }
 }
-
-// Parse client platform string for platform identifier
-// and return corresponding platform.
-func getClientPlatform(clientPlatformString string) string {
-	platform := CLIENT_PLATFORM_WINDOWS
-
-	if strings.Contains(strings.ToLower(clientPlatformString), strings.ToLower(CLIENT_PLATFORM_ANDROID)) {
-		platform = CLIENT_PLATFORM_ANDROID
-	}
-
-	return platform
-}

+ 27 - 0
psiphon/server/safetyNet.go

@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, 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/>.
+ *
+ */
+
+package server
+
+func verifySafetyNetPayload(params requestJSONObject) bool {
+
+	// TODO: implement
+
+	return true
+}