4833526 [rkeene@sledge /home/rkeene/tmp]$ cat -n ssh-agent.cr
  1 require "duktape"
  2 require "socket"
  3 
  4 def readFramed(socket)
  5     inputLen = socket.read_bytes(UInt32, IO::ByteFormat::BigEndian);
  6 
  7     input = Bytes.new(inputLen);
  8     socket.read(input);
  9 
 10     return(input)
 11 end
 12 
 13 def writeFramed(socket, message)
 14     socket.write_bytes(UInt32.new(message.size), IO::ByteFormat::BigEndian);
 15     socket.write(message);
 16 
 17     return(message.size);
 18 end
 19 
 20 def pushArray(ctx, data)
 21     arrIdx  = ctx.push_array();
 22     dataLen = data.size
 23 
 24     idx = UInt32.new(0);
 25     while idx < dataLen
 26         ctx.push_uint(data[idx]);
 27         ctx.put_prop_index(arrIdx, idx);
 28         idx += 1;
 29     end
 30 
 31     return(nil);
 32 end
 33 
 34 def getArray(ctx, stackIndex)
 35     dataLen = ctx.get_length(stackIndex);
 36     data    = Bytes.new(dataLen);
 37 
 38     idx = UInt32.new(0);
 39     while idx < dataLen
 40         ctx.get_prop_index(stackIndex, idx);
 41         data[idx] = UInt8.new(ctx.get_uint(-1));
 42         ctx.pop();
 43         idx += 1;
 44     end
 45 
 46     return(data);
 47 end
 48 
 49 def initJS()
 50     ctx = Duktape::Context.new();
 51     ctx.eval_file_noresult!("chrome-emu.js");
 52     ctx.eval_file_noresult!("ssh-agent-noasync.js");
 53 
 54     ctx.push_global_proc("writeFramed", 2) {|ptr|
 55         msgCtx = Duktape::Context.new(ptr);
 56         socket = Box(UNIXSocket).unbox(msgCtx.get_pointer(0));
 57         data   = getArray(msgCtx, 1);
 58 
 59         writeFramed(socket, data);
 60 
 61         0;
 62     }
 63 
 64     ctx.push_global_proc("cackeyListCertificates", 0) {|ptr|
 65         msgCtx = Duktape::Context.new(ptr);
 66         pushArray(msgCtx, Bytes.new(0));
 67         1;
 68     }
 69 
 70     ctx.eval! <<-EOF
 71         var goog = {DEBUG: true};
 72         cackeySSHAgentFeatures.enabled = true;
 73 
 74         function connection(callback) {
 75             this.sender = {
 76                 id: "pnhechapfaindjhompbnflcldabbghjo"
 77             };
 78             this.onMessage = {
 79                 listeners: [],
 80                 addListener: function(callback) {
 81                     this.listeners.push(callback);
 82                 }
 83             };
 84             this.postMessage = function(message) {
 85                 return(callback(this, message));
 86             };
 87             this.send = function(message) {
 88                 this.onMessage.listeners.forEach(function(listener) {
 89                     listener(message);
 90                 });
 91             };
 92         }
 93 
 94         function handleDataFromAgent(socket, data) {
 95             if (!data || !data.type || !data.data) {
 96                 return;
 97             }
 98 
 99             if (data.type != "auth-agent@openssh.com") {
100                 return;
101             }
102 
103             writeFramed(socket.handle, data.data);
104         }
105 
106         function handleDataFromSocket(socket, data) {
107             socket.send({
108                 type: "auth-agent@openssh.com",
109                 data: data
110             });
111         }
112 EOF
113 
114     return(ctx);
115 end
116 
117 def incomingConnection(socket)
118     # Createa a JavaScript instance to deal with this socket
119     ctx = initJS();
120 
121     # Create a socket handle on the JavaScript side that
122     # corresponds to the Crystal handle
123     ctx.eval!("var socket = new connection(handleDataFromAgent);");
124 
125     # Link the Crystal handle to the JavaScript handle
126     ctx.get_global_string("socket");
127     ctx.push_pointer(Box.box(socket));
128     ctx.put_prop_string(-2, "handle");
129 
130     # Notify the agent that we have received a connection
131     ctx.eval!("chrome.runtime.externalConnect(socket);");
132 
133     while true
134         begin
135             # Read a packet from the peer
136             input = readFramed(socket);
137 
138             # Send that packet to the agent
139             ctx.get_global_string("handleDataFromSocket");
140             ctx.get_global_string("socket");
141             pushArray(ctx, input);
142             ctx.call(2);
143             if ctx.is_error(-1)
144                 puts("Error: #{ctx.json_encode(-1)}");
145                 break
146             end
147 
148             ctx.pop();
149         rescue
150             break
151         end
152     end
153 
154     socket.close();
155 end
156 
157 listener = UNIXServer.new("./agent");
158 while socket = listener.accept?
159     spawn incomingConnection(socket);
160 end
4833527 [rkeene@sledge /home/rkeene/tmp]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2019-06-11 21:47:36