diff --git a/build.zig.zon b/build.zig.zon index fbe94b6..81a653c 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -12,12 +12,12 @@ .hash = "12208c654deea149cee27eaa45d0e6515c3d8f97d775a4156cbcce0ff424b5d26ea3", }, .universal_lambda_build = .{ - .url = "https://git.lerch.org/lobo/universal-lambda-zig/archive/d8b536651531ee95ceb4fae65ca5f29c5ed6ef29.tar.gz", - .hash = "1220de5b5f23fddb794e2e735ee8312b9cd0d1302d5b8e3902f785e904f515506ccf", + .url = "https://git.lerch.org/lobo/universal-lambda-zig/archive/6c89380fea51686b775a93d9a68150262a20d513.tar.gz", + .hash = "1220173c05fa58d0dceda2e2de99edb1a68b859006747cfcf80d7c908dda95f87db2", }, .flexilib = .{ - .url = "https://git.lerch.org/lobo/flexilib/archive/c44ad2ba84df735421bef23a2ad612968fb50f06.tar.gz", - .hash = "122051fdfeefdd75653d3dd678c8aa297150c2893f5fad0728e0d953481383690dbc", + .url = "https://git.lerch.org/lobo/flexilib/archive/3d3dab9c792651477932e2b61c9f4794ac694dcb.tar.gz", + .hash = "1220fd7a614fe3c9f6006b630bba528e2ec9dca9c66f5ff10f7e471ad2bdd41b6c89", }, }, } diff --git a/src/createtable.zig b/src/createtable.zig index 26d4d9f..b7a2a7d 100644 --- a/src/createtable.zig +++ b/src/createtable.zig @@ -1,7 +1,7 @@ const std = @import("std"); const sqlite = @import("sqlite"); -pub fn handler(allocator: std.mem.Allocator, event_data: []const u8) ![]const u8 { +pub fn handler(allocator: std.mem.Allocator, account_id: []const u8, event_data: []const u8) ![]const u8 { _ = event_data; var db = try sqlite.Db.init(.{ .mode = sqlite.Db.Mode{ .File = "donotuse.db" }, @@ -11,9 +11,29 @@ pub fn handler(allocator: std.mem.Allocator, event_data: []const u8) ![]const u8 }, .threading_mode = .MultiThread, }); + // DDB minimum table name length is 3. DDB local creates this table with metadata + // This of course is only if the database is first run + // try db.exec( + // \\CREATE TABLE dm ( + // \\ TableName TEXT, + // \\ CreationDateTime INTEGER, + // \\ LastDecreaseDate INTEGER, + // \\ LastIncreaseDate INTEGER, + // \\ NumberOfDecreasesToday INTEGER, + // \\ ReadCapacityUnits INTEGER, + // \\ WriteCapacityUnits INTEGER, + // \\ TableInfo BLOB, + // \\ BillingMode INTEGER DEFAULT 0, + // \\ PayPerRequestDateTime INTEGER DEFAULT 0, + // \\ PRIMARY KEY(TableName) + // ); try db.exec("CREATE TABLE user(id integer primary key, age integer, name text)", .{}, .{}); var al = std.ArrayList(u8).init(allocator); var writer = al.writer(); - try writer.print("table created\n", .{}); + try writer.print("table created for account {s}\n", .{account_id}); return al.items; + + // This is what the music collection sample creates + // CREATE TABLE IF NOT EXISTS "MusicCollection" (hashKey TEXT DEFAULT NULL, rangeKey TEXT DEFAULT NULL, hashValue BLOB NOT NULL, rangeValue BLOB NOT NULL, itemSize INTEGER DEFAULT 0, ObjectJSON BLOB NOT NULL, PRIMARY KEY(hashKey, rangeKey)); + // CREATE INDEX "MusicCollection*HVI" ON "MusicCollection" (hashValue); } diff --git a/src/main.zig b/src/main.zig index 14167e3..a25d070 100644 --- a/src/main.zig +++ b/src/main.zig @@ -7,8 +7,8 @@ pub const std_options = struct { pub const log_scope_levels = &[_]std.log.ScopeLevel{.{ .scope = .aws_signing, .level = .info }}; }; -pub fn main() !void { - try universal_lambda.run(null, handler); +pub fn main() !u8 { + return try universal_lambda.run(null, handler); } var test_credential: signing.Credentials = undefined; @@ -39,17 +39,38 @@ pub fn handler(allocator: std.mem.Allocator, event_data: []const u8, context: un // X-Amz-Target: DynamoDB_20120810.CreateTable const target_value = headers.http_headers.getFirstValue("X-Amz-Target").?; const operation = target_value[std.mem.lastIndexOf(u8, target_value, ".").? + 1 ..]; + const account_id = try accountId(allocator, headers.http_headers.*); if (std.ascii.eqlIgnoreCase("CreateTable", operation)) - return @import("createtable.zig").handler(allocator, event_data); + return @import("createtable.zig").handler(allocator, account_id, event_data); try std.io.getStdErr().writer().print("Operation '{s}' unsupported\n", .{operation}); return error.OperationUnsupported; } +// TODO: Get hook these functions up to IAM for great good fn getCreds(access: []const u8) ?signing.Credentials { if (std.mem.eql(u8, access, "ACCESS")) return test_credential; return null; } +fn accountForAccessKey(allocator: std.mem.Allocator, access_key: []const u8) ![]const u8 { + _ = allocator; + _ = access_key; + return "1234, Get your woman, on the floor"; +} +/// Function assumes an authenticated request, so signing.verify must be called +/// and returned true before calling this function. If authentication header +/// is not found, environment variable will be used +fn accountId(allocator: std.mem.Allocator, headers: std.http.Headers) ![]const u8 { + const auth_header = headers.getFirstValue("Authorization"); + if (auth_header) |h| { + // AWS4-HMAC-SHA256 Credential=ACCESS/20230908/us-west-2/s3/aws4_request, SignedHeaders=accept;content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-storage-class, Signature=fcc43ce73a34c9bd1ddf17e8a435f46a859812822f944f9eeb2aabcd64b03523 + const start = std.mem.indexOf(u8, h, "Credential=").? + "Credential=".len; + var split = std.mem.split(u8, h[start..], "/"); + return try accountForAccessKey(allocator, split.first()); + } + return try iamAccountId(allocator); +} + // These never need to be freed because we will need them throughout the program var iam_account_id: ?[]const u8 = null; var iam_access_key: ?[]const u8 = null; @@ -70,9 +91,9 @@ fn iamSecretKey(allocator: std.mem.Allocator) ![]const u8 { return try getVariable(allocator, &iam_secret_key, "IAM_SECRET_KEY"); } fn getVariable(allocator: std.mem.Allocator, global: *?[]const u8, env_var_name: []const u8) ![]const u8 { - if (global) |gl| return gl; - global = try std.process.getEnvVarOwned(allocator, env_var_name); - return global.?; + if (global.*) |gl| return gl; + global.* = try std.process.getEnvVarOwned(allocator, env_var_name); + return global.*.?; } test "simple test" {