╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ ssh.zig ──────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
810 }; 811 812 // runs proto.handleConnection in a concurrent task (spawned via std.Io.concurrent). 813 // also acts as the session handler — captures the authenticated key's 814 // fingerprint and returns immediately, leaving runChannelLayer's wrap-up to 815 // send exit-status / EOF / CLOSE. records any error so the test can assert 816 // on it after awaiting the future. 817 const ServerTask = struct { 818 io: std.Io, 819 allocator: std.mem.Allocator, 820 host_key: *const proto.HostKey, 821 reader: *std.Io.Reader, 822 writer: *std.Io.Writer, 823 outgoing: *Pipe, // closed on exit so the client's reads return EOF 824 captured_fp: [proto.fingerprint_len]u8 = undefined, 825 captured_exec_buf: [256]u8 = undefined, 826 captured_exec_len: usize = 0, 827 result: ?anyerror = null, 828 829 pub fn handleSession(self: *ServerTask, sess: *proto.SessionCtx, request: proto.Request) !void { 830 @memcpy(&self.captured_fp, &sess.fingerprint); 831 switch (request) { 832 .exec => |cmd| { 833 // copy out of the protocol's stack-scoped buffer so the 834 // test can assert on it after the handler returns. 835 @memcpy(self.captured_exec_buf[0..cmd.len], cmd); 836 self.captured_exec_len = cmd.len; 837 }, 838 .shell => {}, 839 } 840 } 841 842 fn run(self: *ServerTask) void { 843 defer self.outgoing.close(self.io); 844 proto.handleConnection( 845 self.io, 846 self.allocator, 847 self.reader, 848 self.writer, 849 self.host_key, 850 null, 851 self, 852 ) catch |e| { 853 self.result = e; 854 }; 855 } 856 }; 857 858 // deterministic keys so failures don't depend on RNG state. 859 860 fn newHostKey() !proto.HostKey { 861 const seed = [_]u8{0xAA} ** Ed25519.KeyPair.seed_length; 862 return .{ .keypair = try Ed25519.KeyPair.generateDeterministic(seed) }; 863 } 864 865 fn newUserKeypair() !Ed25519.KeyPair { 866 const seed = [_]u8{0xBB} ** Ed25519.KeyPair.seed_length; 867 return try Ed25519.KeyPair.generateDeterministic(seed); 868 } 869 870 fn newClientEphemeral() !X25519.KeyPair { 871 const seed = [_]u8{0xCC} ** X25519.seed_length; 872 return try X25519.KeyPair.generateDeterministic(seed); 873 } 874