Skip to content

Commit b617e83

Browse files
committed
Validate server profile sent from user.
1 parent 2da51dd commit b617e83

File tree

1 file changed

+122
-5
lines changed

1 file changed

+122
-5
lines changed

ShadowsocksX-NG/HTTPUserProxy.swift

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class HTTPUserProxy{
1313
static let shard = HTTPUserProxy()
1414

1515
let adapter = APIAdapter()
16+
let v = Validator()
1617

1718
let server = GCDWebServer()
1819
let api_port:UInt = 9528
@@ -84,7 +85,7 @@ class HTTPUserProxy{
8485
func addHandler_getCurrentServer() {
8586
server.addHandler(forMethod: "GET", path: "/current", request: GCDWebServerRequest.self, processBlock: {request in
8687
if let activeId = self.adapter.getCurrentServerId() {
87-
return GCDWebServerDataResponse(jsonObject: self.adapter.getServer(uuid: activeId), contentType: "json")
88+
return GCDWebServerDataResponse(jsonObject: self.adapter.getServer(uuid: activeId)!, contentType: "json")
8889
}
8990
else {
9091
return GCDWebServerResponse(statusCode: 404);
@@ -110,7 +111,7 @@ class HTTPUserProxy{
110111
if var server = ((request as? GCDWebServerURLEncodedFormRequest)?.arguments) as? [String: Any] {
111112
if (server["ServerPort"] != nil) {
112113
server["ServerPort"] = UInt16(server["ServerPort"] as! String)
113-
if (true) { // validate
114+
if (Validator.integrity(server) && Validator.existAttributes(server)) { // validate
114115
self.adapter.addServer(server: server)
115116
return GCDWebServerResponse();
116117
}
@@ -128,7 +129,7 @@ class HTTPUserProxy{
128129
server["ServerPort"] = UInt16(server["ServerPort"] as! String)
129130
}
130131
if (self.adapter.getServer(uuid: id) != nil) {
131-
if (true) { // validate
132+
if (Validator.existAttributes(server)) {
132133
if (self.adapter.getCurrentServerId() != id) {
133134
self.adapter.modifyServer(uuid: id, server: server)
134135
return GCDWebServerResponse()
@@ -185,7 +186,7 @@ class HTTPUserProxy{
185186

186187
class APIAdapter {
187188
enum Mode:String {case auto="auto", global="global", manual="manual"};
188-
189+
189190
let SerMgr = ServerProfileManager.instance
190191
let defaults = UserDefaults.standard
191192
let appdeleget = NSApplication.shared.delegate as! AppDelegate
@@ -262,7 +263,6 @@ class APIAdapter {
262263
}
263264
if (server["Plugin"] != nil) {
264265
profile.plugin = server["Plugin"] as! String;
265-
266266
}
267267
if (server["PluginOptions"] != nil) {
268268
profile.pluginOptions = server["PluginOptions"] as! String;
@@ -304,3 +304,120 @@ class APIAdapter {
304304
self.appdeleget.applyConfig()
305305
}
306306
}
307+
308+
class Validator {
309+
static func integrity(_ data: Dictionary<String, Any>) -> Bool {
310+
if (data["ServerHost"] == nil || data["ServerPort"] as? NSNumber == nil
311+
|| data["Method"] == nil || data["Password"] == nil) {
312+
return false;
313+
}
314+
return true;
315+
}
316+
317+
static func existAttributes(_ server:Dictionary<String, Any>) -> Bool {
318+
var result = true;
319+
320+
if (server["ServerHost"] != nil) {
321+
result = result && serverHost(server["ServerHost"] as! String);
322+
}
323+
if (server["ServerPort"] != nil) {
324+
result = result && serverPort(server["ServerPort"] as! uint16);
325+
}
326+
if (server["Method"] != nil) {
327+
result = result && method(server["Method"] as! String);
328+
}
329+
if (server["Password"] != nil) {
330+
result = result && password(server["Password"] as! String);
331+
}
332+
if (server["Remark"] != nil) {
333+
result = result && remark(server["Remark"] as! String);
334+
}
335+
if (server["Plugin"] != nil) {
336+
result = result && plugin(server["Plugin"] as! String);
337+
}
338+
if (server["PluginOptions"] != nil) {
339+
result = result && pluginOptions(server["PluginOptions"] as! String);
340+
}
341+
342+
return result;
343+
}
344+
345+
static func serverHost(_ str:String) -> Bool {
346+
return validateIpAddress(str) || validateDomainName(str);
347+
}
348+
349+
static func serverPort(_ str:uint16) -> Bool {
350+
return true;
351+
}
352+
353+
static func method(_ str:String) -> Bool {
354+
// Copy from PreferencesWindowController.swift
355+
// Better to make valid methods enumeration type.
356+
return [
357+
"aes-128-gcm",
358+
"aes-192-gcm",
359+
"aes-256-gcm",
360+
"aes-128-cfb",
361+
"aes-192-cfb",
362+
"aes-256-cfb",
363+
"aes-128-ctr",
364+
"aes-192-ctr",
365+
"aes-256-ctr",
366+
"camellia-128-cfb",
367+
"camellia-192-cfb",
368+
"camellia-256-cfb",
369+
"bf-cfb",
370+
"chacha20-ietf-poly1305",
371+
"xchacha20-ietf-poly1305",
372+
"salsa20",
373+
"chacha20",
374+
"chacha20-ietf",
375+
"rc4-md5",
376+
].contains(str);
377+
}
378+
379+
static func password(_ str:String) -> Bool {
380+
return true;
381+
}
382+
383+
static func remark(_ str:String) -> Bool {
384+
return true;
385+
}
386+
387+
static func plugin(_ str:String) -> Bool {
388+
return true;
389+
}
390+
391+
static func pluginOptions(_ str:String) -> Bool {
392+
return true;
393+
}
394+
395+
// Copy from ServerProfile.swift
396+
private static func validateIpAddress(_ ipToValidate: String) -> Bool {
397+
398+
var sin = sockaddr_in()
399+
var sin6 = sockaddr_in6()
400+
401+
if ipToValidate.withCString({ cstring in inet_pton(AF_INET6, cstring, &sin6.sin6_addr) }) == 1 {
402+
// IPv6 peer.
403+
return true
404+
}
405+
else if ipToValidate.withCString({ cstring in inet_pton(AF_INET, cstring, &sin.sin_addr) }) == 1 {
406+
// IPv4 peer.
407+
return true
408+
}
409+
410+
return false;
411+
}
412+
413+
// Copy from ServerProfile.swift
414+
private static func validateDomainName(_ value: String) -> Bool {
415+
let validHostnameRegex = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$"
416+
417+
if (value.range(of: validHostnameRegex, options: .regularExpression) != nil) {
418+
return true
419+
} else {
420+
return false
421+
}
422+
}
423+
}

0 commit comments

Comments
 (0)