1
0
Fork 0
QuasselClient/src/client.zig
2021-06-05 08:55:43 +01:00

174 lines
6.2 KiB
Zig

const std = @import("std");
const read = @import("./qtshit/read.zig");
const write = @import("./qtshit/write.zig");
const range = @import("./qtshit/utils/RangeIter.zig").range;
const QVariantType = @import("./qtshit/types/QVariant.zig").QVariant;
const prettyPrintQVariant = @import("./qtshit/utils/prettyPrintQVariant.zig").prettyPrintQVariant;
const freeQVariant = @import("./qtshit/utils/free/freeQVariant.zig").freeQVariant;
const QVariantMapToQVariantList = @import("./qtshit/utils/QVariantMapToQVariantList.zig").QVariantMapToQVariantList;
const tls = @import("./deps/iguanaTLS/src/main.zig");
fn dumpDebug(name: []const u8, list: std.ArrayList(u8)) !void {
std.debug.print("dumpDebug list len {d}\n", .{list.items.len});
const file = try std.fs.cwd().createFile(
name,
.{ .truncate = true },
);
defer file.close();
try file.seekTo(0);
try file.writeAll(list.items);
}
pub const Client = struct {
allocator: *std.mem.Allocator,
stream: *std.net.Stream,
pub var tlsAllowed = !true;
pub var tlsConnected = !true;
pub const TLSStream = tls.Client(std.net.Stream.Reader, std.net.Stream.Writer, tls.ciphersuites.all, false);
pub var tlsClient: TLSStream = undefined;
pub fn initTLS(s: *Client) !void {
if (!tlsConnected and tlsAllowed) {
var randBuf: [32]u8 = undefined;
try std.os.getrandom(&randBuf);
var rng = std.rand.DefaultCsprng.init(randBuf);
var rand = blk: {
var seed: [std.rand.DefaultCsprng.secret_seed_length]u8 = undefined;
try std.os.getrandom(&seed);
break :blk &std.rand.DefaultCsprng.init(seed).random;
};
tlsClient = try tls.client_connect(.{
.rand = rand,
.temp_allocator = s.allocator,
.reader = s.stream.reader(),
.writer = s.stream.writer(),
.cert_verifier = .none,
.ciphersuites = tls.ciphersuites.all,
}, "quassel.owo.monster");
}
}
pub fn _writeFrame(s: *Client, writer: anytype, data: std.ArrayList(u8)) !void {
try write.writeUInt(writer, @intCast(u32, data.items.len));
try writer.writeAll(data.items);
}
pub fn writeFrame(s: *Client, data: std.ArrayList(u8)) !void {
try s.initTLS();
if (tlsConnected) {
var writer = tlsClient.writer();
try s._writeFrame(writer, data);
} else {
var writer = s.stream.writer();
try s._writeFrame(writer, data);
}
}
pub fn _readFrame(s: *Client, reader: anytype) !std.ArrayList(u8) {
var size = try read.readUInt(reader);
var data = std.ArrayList(u8).init(s.allocator);
var iter = range(u32, 0, size);
while (iter.next()) |i| {
const byte = try reader.readByte();
try data.append(byte);
}
return data;
}
pub fn readFrame(s: *Client) !QVariantType {
try s.initTLS();
var data: std.ArrayList(u8) = undefined;
if (tlsConnected) {
var reader = tlsClient.reader();
data = try s._readFrame(reader);
} else {
var reader = s.stream.reader();
data = try s._readFrame(reader);
}
var fBS = std.io.fixedBufferStream(data.items);
return try read.readQVariant(fBS.reader(), s.allocator);
}
pub fn handshake(s: *Client) !void {
//const magic = 0x42b33f00;
//try write.writeUInt(s.stream.writer(), magic);
//try write.writeUInt(s.stream.writer(), 0x80000002);
try s.stream.writer().writeAll(&[_]u8{ 0x42, 0xb3, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00 });
var flags = try read.readByte(s.stream.reader());
var extra = try read.readShort(s.stream.reader());
var version = try read.readSignedByte(s.stream.reader());
std.debug.print("Handshake: flags={d} extra={d} version={d} \n", .{ flags, extra, version });
}
pub fn quassel_init_packet(s: *Client) !void {
var data = std.ArrayList(u8).init(s.allocator);
var map = std.StringHashMap(QVariantType).init(s.allocator);
try map.put("MsgType", .{ .String = "ClientInit" });
try map.put("UseCompression", .{ .UInt = 0 });
try map.put("UseSsl", .{ .UInt = 1 });
try map.put("ProtocolVersion", .{ .UInt = 10 });
try map.put("ClientVersion", .{ .String = "0.1 (quasselclient)" });
try map.put("ClientDate", .{ .String = "Wed, 02 Jun 2021 17:30:30 +0100" });
try map.put("Features", .{ .Int = 0x00008000 });
var featureList = std.ArrayList([]const u8).init(s.allocator);
defer featureList.deinit();
try featureList.append("LongTime");
try featureList.append("LongMessageID");
try featureList.append("SenderPrefixes");
try featureList.append("RichMessages");
try map.put("FeatureList", .{ .QStringList = featureList.items });
try write.writeQVariant(data.writer(), s.allocator, .{
.QVariantMap = map,
});
try s.writeFrame(data);
var varient = try s.readFrame();
tlsAllowed = varient.QVariantMap.get("SupportSsl").?.Byte == 1;
prettyPrintQVariant(varient, 0);
freeQVariant(varient, s.allocator);
}
pub fn quassel_login(s: *Client, username: []const u8, password: []const u8) !void {
var data = std.ArrayList(u8).init(s.allocator);
var map = std.StringHashMap(QVariantType).init(s.allocator);
try map.put("MsgType", .{ .String = "ClientLogin" });
try map.put("User", .{ .String = username });
try map.put("Password", .{ .String = password });
try write.writeQVariant(data.writer(), s.allocator, .{
.QVariantMap = map,
});
try s.writeFrame(data);
}
pub fn read_quassel_packet(s: *Client) !void {
std.debug.print("\n\nQuassel Packet: \n", .{});
var varient = try s.readFrame();
prettyPrintQVariant(varient, 0);
freeQVariant(varient, s.allocator);
}
};
pub fn initClient(allocator: *std.mem.Allocator, stream: *std.net.Stream) Client {
return Client{
.allocator = allocator,
.stream = stream,
};
}