Files
bun.sh/src/sql/postgres/protocol/Authentication.zig
Ciro Spaciari ecbf103bf5 feat(MYSQL) Bun.SQL mysql support (#21968)
### What does this PR do?
Add MySQL support, Refactor will be in a followup PR
### How did you verify your code works?
A lot of tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: cirospaciari <6379399+cirospaciari@users.noreply.github.com>
2025-08-21 15:28:15 -07:00

181 lines
5.4 KiB
Zig

pub const Authentication = union(enum) {
Ok: void,
ClearTextPassword: struct {},
MD5Password: struct {
salt: [4]u8,
},
KerberosV5: struct {},
SCMCredential: struct {},
GSS: struct {},
GSSContinue: struct {
data: Data,
},
SSPI: struct {},
SASL: struct {},
SASLContinue: struct {
data: Data,
r: []const u8,
s: []const u8,
i: []const u8,
pub fn iterationCount(this: *const @This()) !u32 {
return try std.fmt.parseInt(u32, this.i, 0);
}
},
SASLFinal: struct {
data: Data,
},
Unknown: void,
pub fn deinit(this: *@This()) void {
switch (this.*) {
.MD5Password => {},
.SASL => {},
.SASLContinue => {
this.SASLContinue.data.zdeinit();
},
.SASLFinal => {
this.SASLFinal.data.zdeinit();
},
else => {},
}
}
pub fn decodeInternal(this: *@This(), comptime Container: type, reader: NewReader(Container)) !void {
const message_length = try reader.length();
switch (try reader.int4()) {
0 => {
if (message_length != 8) return error.InvalidMessageLength;
this.* = .{ .Ok = {} };
},
2 => {
if (message_length != 8) return error.InvalidMessageLength;
this.* = .{
.KerberosV5 = .{},
};
},
3 => {
if (message_length != 8) return error.InvalidMessageLength;
this.* = .{
.ClearTextPassword = .{},
};
},
5 => {
if (message_length != 12) return error.InvalidMessageLength;
var salt_data = try reader.bytes(4);
defer salt_data.deinit();
this.* = .{
.MD5Password = .{
.salt = salt_data.slice()[0..4].*,
},
};
},
7 => {
if (message_length != 8) return error.InvalidMessageLength;
this.* = .{
.GSS = .{},
};
},
8 => {
if (message_length < 9) return error.InvalidMessageLength;
const bytes = try reader.read(message_length - 8);
this.* = .{
.GSSContinue = .{
.data = bytes,
},
};
},
9 => {
if (message_length != 8) return error.InvalidMessageLength;
this.* = .{
.SSPI = .{},
};
},
10 => {
if (message_length < 9) return error.InvalidMessageLength;
try reader.skip(message_length - 8);
this.* = .{
.SASL = .{},
};
},
11 => {
if (message_length < 9) return error.InvalidMessageLength;
var bytes = try reader.bytes(message_length - 8);
errdefer {
bytes.deinit();
}
var iter = bun.strings.split(bytes.slice(), ",");
var r: ?[]const u8 = null;
var i: ?[]const u8 = null;
var s: ?[]const u8 = null;
while (iter.next()) |item| {
if (item.len > 2) {
const key = item[0];
const after_equals = item[2..];
if (key == 'r') {
r = after_equals;
} else if (key == 's') {
s = after_equals;
} else if (key == 'i') {
i = after_equals;
}
}
}
if (r == null) {
debug("Missing r", .{});
}
if (s == null) {
debug("Missing s", .{});
}
if (i == null) {
debug("Missing i", .{});
}
this.* = .{
.SASLContinue = .{
.data = bytes,
.r = r orelse return error.InvalidMessage,
.s = s orelse return error.InvalidMessage,
.i = i orelse return error.InvalidMessage,
},
};
},
12 => {
if (message_length < 9) return error.InvalidMessageLength;
const remaining: usize = message_length - 8;
const bytes = try reader.read(remaining);
this.* = .{
.SASLFinal = .{
.data = bytes,
},
};
},
else => {
this.* = .{ .Unknown = {} };
},
}
}
pub const decode = DecoderWrap(Authentication, decodeInternal).decode;
};
const debug = bun.Output.scoped(.Postgres, .hidden);
const bun = @import("bun");
const std = @import("std");
const Data = @import("../../shared/Data.zig").Data;
const DecoderWrap = @import("./DecoderWrap.zig").DecoderWrap;
const NewReader = @import("./NewReader.zig").NewReader;