home + shell validators
This commit is contained in:
parent
7911287261
commit
5d171883a7
16
src/User.zig
16
src/User.zig
@ -57,14 +57,12 @@ fn fromLine(allocator: Allocator, err: *ErrCtx, line: []const u8) error{ Invalid
|
|||||||
const shell = it.next();
|
const shell = it.next();
|
||||||
|
|
||||||
// all fields are set
|
// all fields are set
|
||||||
if (shell == null) {
|
if (shell == null)
|
||||||
err.print("too few user fields in line: {s}", .{line});
|
return err.returnf("too few user fields in line: {s}", .{line}, error.InvalidRecord);
|
||||||
return error.InvalidRecord;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the line must be exhaustive.
|
// the line must be exhaustive.
|
||||||
if (it.next() != null)
|
if (it.next() != null)
|
||||||
return error.InvalidRecord;
|
return error.returnf("too many fields in line", .{}, error.InvalidRecord);
|
||||||
|
|
||||||
const uid = fmt.parseInt(u32, uids.?, 10) catch
|
const uid = fmt.parseInt(u32, uids.?, 10) catch
|
||||||
return err.returnf("bad uid: {s}", .{uids.?}, error.InvalidRecord);
|
return err.returnf("bad uid: {s}", .{uids.?}, error.InvalidRecord);
|
||||||
@ -76,10 +74,10 @@ fn fromLine(allocator: Allocator, err: *ErrCtx, line: []const u8) error{ Invalid
|
|||||||
return err.returnf("invalid name '{s}'", .{name.?}, error.InvalidRecord);
|
return err.returnf("invalid name '{s}'", .{name.?}, error.InvalidRecord);
|
||||||
validate.gecos(gecos.?, err) catch
|
validate.gecos(gecos.?, err) catch
|
||||||
return err.returnf("invalid gecos '{s}'", .{gecos.?}, error.InvalidRecord);
|
return err.returnf("invalid gecos '{s}'", .{gecos.?}, error.InvalidRecord);
|
||||||
validate.utf8(home.?) catch
|
validate.path(home.?, err) catch
|
||||||
return err.returnf("home is invalid utf8: '{s}'", .{home.?}, error.InvalidRecord);
|
return err.returnf("invalid home '{s}'", .{home.?}, error.InvalidRecord);
|
||||||
validate.utf8(shell.?) catch
|
validate.path(shell.?, err) catch
|
||||||
return err.returnf("shell is invalid utf8: '{s}'", .{shell.?}, error.InvalidRecord);
|
return err.returnf("invalid shell '{s}'", .{shell.?}, error.InvalidRecord);
|
||||||
|
|
||||||
const user = User{
|
const user = User{
|
||||||
.uid = uid,
|
.uid = uid,
|
||||||
|
@ -45,7 +45,24 @@ pub fn gecos(s: []const u8, errc: *ErrCtx) error{InvalidRecord}!void {
|
|||||||
var it = utf8view.iterator();
|
var it = utf8view.iterator();
|
||||||
while (it.nextCodepoint()) |codepoint| {
|
while (it.nextCodepoint()) |codepoint| {
|
||||||
if (codepoint == ':')
|
if (codepoint == ':')
|
||||||
return errc.returnf(": is not allowed", .{}, error.InvalidRecord);
|
return errc.returnf("colon is not allowed", .{}, error.InvalidRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path(s: []const u8, err: *ErrCtx) error{InvalidRecord}!void {
|
||||||
|
if (s.len == 0)
|
||||||
|
return err.returnf("cannot be empty", .{}, error.InvalidRecord);
|
||||||
|
|
||||||
|
if (s[0] != '/')
|
||||||
|
return err.returnf("must start with '/'", .{}, error.InvalidRecord);
|
||||||
|
|
||||||
|
for (s[1..]) |c, i| {
|
||||||
|
if (!(ascii.isAlNum(c) or c == '/' or c == '_' or c == '.' or c == '@' or c == '-'))
|
||||||
|
return err.returnf(
|
||||||
|
"invalid character at position {d}",
|
||||||
|
.{i + 2},
|
||||||
|
error.InvalidRecord,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +104,7 @@ test "validate gecos" {
|
|||||||
.{ .gecos = "" },
|
.{ .gecos = "" },
|
||||||
.{ .gecos = "Vidmantas Kaminskas Ž" },
|
.{ .gecos = "Vidmantas Kaminskas Ž" },
|
||||||
.{ .gecos = "Not\xffUnicode", .wantErr = "invalid utf8" },
|
.{ .gecos = "Not\xffUnicode", .wantErr = "invalid utf8" },
|
||||||
.{ .gecos = "Has:Colon", .wantErr = ": is not allowed" },
|
.{ .gecos = "Has:Colon", .wantErr = "colon is not allowed" },
|
||||||
};
|
};
|
||||||
for (examples) |tt| {
|
for (examples) |tt| {
|
||||||
var err = ErrCtx{};
|
var err = ErrCtx{};
|
||||||
@ -103,3 +120,30 @@ test "validate gecos" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "validate path" {
|
||||||
|
const examples = [_]struct {
|
||||||
|
path: []const u8,
|
||||||
|
wantErr: ?[]const u8 = null,
|
||||||
|
}{
|
||||||
|
.{ .path = "/path/ok" },
|
||||||
|
.{ .path = "/" },
|
||||||
|
.{ .path = "foo", .wantErr = "must start with '/'" },
|
||||||
|
.{ .path = "", .wantErr = "cannot be empty" },
|
||||||
|
.{ .path = "/path:motiejus", .wantErr = "invalid character at position 6" },
|
||||||
|
.{ .path = "/Herbasž", .wantErr = "invalid character at position 8" },
|
||||||
|
};
|
||||||
|
for (examples) |tt| {
|
||||||
|
var err = ErrCtx{};
|
||||||
|
|
||||||
|
const got = path(tt.path, &err);
|
||||||
|
if (tt.wantErr) |wantErr| {
|
||||||
|
try testing.expectError(error.InvalidRecord, got);
|
||||||
|
try testing.expectEqualStrings(wantErr, err.unwrap().constSlice());
|
||||||
|
} else {
|
||||||
|
// TODO: how to assert `got` is a non-error in a single line?
|
||||||
|
if (got) |_| {} else |_| return error.TestUnExpectedError;
|
||||||
|
try testing.expectEqualStrings("", err.unwrap().constSlice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user