Explorar el Código

lua: Minimal implementation of ssl (#10593)

* lua: Minimal implementation of ssl

Depends on luasec.
The initial implementation is enough to access a webpage over https.

* Install luasec in test environment

* Install openssl when testing the lua target on Mac OS

Required by luasec

* Don't try to link openssl on Mac OS

brew doesn't allow it. Instead we pass the OPENSSL_DIR option to luarocks.

* Don't require luasec when using lua-vanilla
Jaime Marquínez Ferrándiz hace 3 años
padre
commit
e1ced88e13

+ 1 - 73
std/lua/_std/sys/net/Socket.hx

@@ -159,76 +159,4 @@ class Socket {
 		var write_arr = res.write == null ? [] : Table.toArray(res.write).map(convert_socket);
 		var write_arr = res.write == null ? [] : Table.toArray(res.write).map(convert_socket);
 		return {read: read_arr, write: write_arr, others: []};
 		return {read: read_arr, write: write_arr, others: []};
 	}
 	}
-}
-
-private class SocketInput extends haxe.io.Input {
-	var tcp:TcpClient;
-
-	public function new(tcp:TcpClient) {
-		this.tcp = tcp;
-	}
-
-	override public function readByte():Int {
-		var res = tcp.receive(1);
-		if (res.message == "closed"){
-			throw new haxe.io.Eof();
-		}
-		else if (res.message != null)
-			throw 'Error : ${res.message}';
-		return res.result.charCodeAt(0);
-	}
-
-	override public function readBytes(s:Bytes, pos:Int, len:Int):Int {
-		var leftToRead = len;
-		var b = s.getData();
-		if (pos < 0 || len < 0 || pos + len > s.length)
-			throw haxe.io.Error.OutsideBounds;
-		var readCount = 0;
-		try {
-			while (leftToRead > 0) {
-				b[pos] = cast readByte();
-				pos++;
-				readCount++;
-				leftToRead--;
-			}
-		} catch (e:haxe.io.Eof) {
-			if (readCount == 0) {
-				throw e;
-			}
-		}
-		return readCount;
-	}
-
-}
-
-private class SocketOutput extends haxe.io.Output {
-	var tcp:TcpClient;
-
-	public function new(tcp:TcpClient) {
-		this.tcp = tcp;
-	}
-
-	override public function writeByte(c:Int):Void {
-		var char = NativeStringTools.char(c);
-		var res = tcp.send(char);
-		if (res.message != null){
-			throw 'Error : Socket writeByte : ${res.message}';
-		}
-	}
-
-	override public function writeBytes(s:Bytes, pos:Int, len:Int):Int {
-		if (pos < 0 || len < 0 || pos + len > s.length)
-			throw Error.OutsideBounds;
-		var b = s.getData().slice(pos, pos +len).map(function(byte){
-			return lua.NativeStringTools.char(byte);
-		});
-		var encoded = Table.concat(cast b, 0);
-		var res = tcp.send(encoded);
-		if (res.message != null){
-			throw 'Error : Socket writeByte : ${res.message}';
-		}
-
-		return len;
-	}
-
-}
+}

+ 69 - 0
std/lua/_std/sys/net/SocketInput.hx

@@ -0,0 +1,69 @@
+/*
+ * Copyright (C)2005-2022 Haxe Foundation
+ *
+ * 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.
+ */
+ 
+package sys.net;
+
+import lua.lib.luasocket.socket.TcpClient;
+import lua.*;
+
+import haxe.io.Bytes;
+import haxe.io.Error;
+
+class SocketInput extends haxe.io.Input {
+	var tcp:TcpClient;
+
+	public function new(tcp:TcpClient) {
+		this.tcp = tcp;
+	}
+
+	override public function readByte():Int {
+		var res = tcp.receive(1);
+		if (res.message == "closed"){
+			throw new haxe.io.Eof();
+		}
+		else if (res.message != null)
+			throw 'Error : ${res.message}';
+		return res.result.charCodeAt(0);
+	}
+
+	override public function readBytes(s:Bytes, pos:Int, len:Int):Int {
+		var leftToRead = len;
+		var b = s.getData();
+		if (pos < 0 || len < 0 || pos + len > s.length)
+			throw haxe.io.Error.OutsideBounds;
+		var readCount = 0;
+		try {
+			while (leftToRead > 0) {
+				b[pos] = cast readByte();
+				pos++;
+				readCount++;
+				leftToRead--;
+			}
+		} catch (e:haxe.io.Eof) {
+			if (readCount == 0) {
+				throw e;
+			}
+		}
+		return readCount;
+	}
+
+}

+ 61 - 0
std/lua/_std/sys/net/SocketOutput.hx

@@ -0,0 +1,61 @@
+/*
+ * Copyright (C)2005-2022 Haxe Foundation
+ *
+ * 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.
+ */
+ 
+package sys.net;
+
+import lua.lib.luasocket.socket.TcpClient;
+import lua.*;
+
+import haxe.io.Bytes;
+import haxe.io.Error;
+
+class SocketOutput extends haxe.io.Output {
+	var tcp:TcpClient;
+
+	public function new(tcp:TcpClient) {
+		this.tcp = tcp;
+	}
+
+	override public function writeByte(c:Int):Void {
+		var char = NativeStringTools.char(c);
+		var res = tcp.send(char);
+		if (res.message != null){
+			throw 'Error : Socket writeByte : ${res.message}';
+		}
+	}
+
+	override public function writeBytes(s:Bytes, pos:Int, len:Int):Int {
+		if (pos < 0 || len < 0 || pos + len > s.length)
+			throw Error.OutsideBounds;
+		var b = s.getData().slice(pos, pos +len).map(function(byte){
+			return lua.NativeStringTools.char(byte);
+		});
+		var encoded = Table.concat(cast b, 0);
+		var res = tcp.send(encoded);
+		if (res.message != null){
+			throw 'Error : Socket writeByte : ${res.message}';
+		}
+
+		return len;
+	}
+
+}

+ 66 - 0
std/lua/_std/sys/ssl/Socket.hx

@@ -0,0 +1,66 @@
+/*
+ * Copyright (C)2005-2022 Haxe Foundation
+ *
+ * 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.
+ */
+
+ package sys.ssl;
+
+ import sys.net.Host;
+ import sys.net.SocketInput;
+ import sys.net.SocketOutput;
+
+ import lua.lib.luasocket.Socket as LuaSocket;
+ import lua.lib.luasec.Ssl as LuaSecSsl;
+ import lua.lib.luasec.SslTcpClient;
+ 
+ import haxe.io.Bytes;
+ import haxe.io.Error;
+ 
+class Socket extends sys.net.Socket { 
+    var _sslSocket:SslTcpClient;
+
+    private function wrap(sock:LuaSocket):SslTcpClient {
+        var res = LuaSecSsl.wrap(sock, {mode: Client, protocol: Any});
+        if (res.message != null) {
+			throw 'Socket Error : ${res.message}';
+        }
+        return res.result;
+    }
+ 
+    public function handshake():Void {
+        var res = this._sslSocket.dohandshake();
+        if (res.message != null) {
+			throw 'Handshake Error : ${res.message}';
+        }
+    }
+
+    public override function connect(host:Host, port:Int):Void {
+        var res = LuaSocket.connect(host.host, port);
+		if (res.message != null)
+			throw 'Socket Error : ${res.message}';
+        var sslSock = this.wrap(res.result);
+		input = new SocketInput(sslSock);
+		output = new SocketOutput(sslSock);
+		_sslSocket = sslSock;
+		_sslSocket.settimeout(timeout);
+        this.handshake();
+    }
+ }
+ 

+ 44 - 0
std/lua/lib/luasec/Ssl.hx

@@ -0,0 +1,44 @@
+/*
+ * Copyright (C)2005-2022 Haxe Foundation
+ *
+ * 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.
+ */
+
+package lua.lib.luasec;
+
+import lua.lib.luasocket.Socket as LuaSocket;
+
+@:luaRequire("ssl")
+extern class Ssl {
+    static function wrap(sock:LuaSocket, params: SslParams):Result<SslTcpClient>;
+}
+
+typedef SslParams = {
+    mode: Mode,
+    protocol: Protocol,
+}
+
+enum abstract Mode(String) {
+    var Client = "client";
+    var Server = "server";
+}
+
+enum abstract Protocol(String) {
+    var Any = "any";
+}

+ 29 - 0
std/lua/lib/luasec/SslTcpClient.hx

@@ -0,0 +1,29 @@
+/*
+ * Copyright (C)2005-2022 Haxe Foundation
+ *
+ * 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.
+ */
+
+package lua.lib.luasec;
+
+import lua.lib.luasocket.socket.TcpClient;
+
+extern class SslTcpClient extends TcpClient {
+    function dohandshake():Result<Bool>;
+}

+ 1 - 1
std/sys/Http.hx

@@ -104,7 +104,7 @@ class Http extends haxe.http.HttpBase {
 				sock = new java.net.SslSocket();
 				sock = new java.net.SslSocket();
 				#elseif python
 				#elseif python
 				sock = new python.net.SslSocket();
 				sock = new python.net.SslSocket();
-				#elseif (!no_ssl && (hxssl || hl || cpp || (neko && !(macro || interp) || eval)))
+				#elseif (!no_ssl && (hxssl || hl || cpp || (neko && !(macro || interp) || eval) || (lua && !lua_vanilla)))
 				sock = new sys.ssl.Socket();
 				sock = new sys.ssl.Socket();
 				#elseif (neko || cpp)
 				#elseif (neko || cpp)
 				throw "Https is only supported with -lib hxssl";
 				throw "Https is only supported with -lib hxssl";

+ 5 - 0
tests/runci/targets/Lua.hx

@@ -23,6 +23,7 @@ class Lua {
 
 
 				attemptCommand("brew", ["install", "pcre"]);
 				attemptCommand("brew", ["install", "pcre"]);
 				runCommand("pip3", ["install", "hererocks"]);
 				runCommand("pip3", ["install", "hererocks"]);
+				runCommand("brew", ["install", "openssl"]);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -30,6 +31,9 @@ class Lua {
 	static function installLib(lib : String, version : String, ?server :String){
 	static function installLib(lib : String, version : String, ?server :String){
 		if (!commandSucceed("luarocks", ["show", lib, version])) {
 		if (!commandSucceed("luarocks", ["show", lib, version])) {
             final args = ["install", lib, version];
             final args = ["install", lib, version];
+			if (systemName == "Mac") {
+				args.push('OPENSSL_DIR=/usr/local/opt/openssl@3');
+			}
             if (server != null){
             if (server != null){
                 final server_arg = '--server=$server';
                 final server_arg = '--server=$server';
                 args.push(server_arg);
                 args.push(server_arg);
@@ -67,6 +71,7 @@ class Lua {
 			// attemptCommand("luarocks", ["config", "--user-config"]);
 			// attemptCommand("luarocks", ["config", "--user-config"]);
 
 
 			installLib("haxe-deps", "0.0.1-6");
 			installLib("haxe-deps", "0.0.1-6");
+			installLib("luasec", "1.0.2-1");
 
 
 			changeDirectory(unitDir);
 			changeDirectory(unitDir);
 			runCommand("haxe", ["compile-lua.hxml"].concat(args));
 			runCommand("haxe", ["compile-lua.hxml"].concat(args));