Get password input

Is there a way to get user input from the terminal without displaying the input? The user should either see nothing or *****.

You might want to try this library, I don’t know if it has the password input feature but you could always add it! Using a readline-type line editor would let your users do basic line editing, it’s always frustrating when the left arrow inserts some control character etc. Line Editing on any platform: Anyline

1 Like

This code is for POSIX systems, not for Windows

const std = @import("std");

fn disableEcho(fd: std.posix.fd_t) !void {
    var termios: std.posix.termios = try std.posix.tcgetattr(fd);
    termios.lflag.ECHO = false;
    try std.posix.tcsetattr(fd, .NOW, termios);
}

fn enableEcho(fd: std.posix.fd_t) !void {
    var termios: std.posix.termios = try std.posix.tcgetattr(fd);
    termios.lflag.ECHO = true;
    try std.posix.tcsetattr(fd, .NOW, termios);
}

pub fn interactivePassword(buf: []u8) ![]u8 {
    const stdin = std.fs.File.stdin();
    try disableEcho(stdin.handle);
    defer enableEcho(stdin.handle) catch unreachable;
    var stdin_reader = stdin.reader(buf);
    return try stdin_reader.interface.takeDelimiterExclusive('\n');
}

pub fn main() !void {
    var buf: [128]u8 = undefined;
    std.debug.print("print password here:", .{});
    const password = try interactivePassword(&buf);
    std.debug.print("\n{s}\n", .{password});
}
3 Likes

Thanks. I ended up using the ICANON flag: termios.lflag.ICANON = false. It gives me more control.

In case someone needs it, here is my solution: GitHub - eltNEG/passprompt: A simple Zig library for secure password input from the terminal with customizable display options

3 Likes

This however will not work for windows, as it is solely focused on posix. After a little bit of scouting the zig 0.15.2 files, I

fn setEchoW(enable: bool) !void {
    const windows = std.os.windows;
    const kernel32 = windows.kernel32;

    const stdout_handle = kernel32.GetStdHandle(windows.STD_INPUT_HANDLE) orelse return error.StdHandleFailed;

    var mode: windows.DWORD = undefined;
    _ = kernel32.GetConsoleMode(stdout_handle, &mode);

    const ENABLE_ECHO_MODE: u32 = 0x0004;
    const new_mode = if (enable) mode | ENABLE_ECHO_MODE else mode & ~ENABLE_ECHO_MODE;
    _ = kernel32.SetConsoleMode(stdout_handle, new_mode);
}

fn setEchoL(enable: bool) !void {
    const fd = std.fs.File.stdin().handle;
    var termios: std.posix.termios = try std.posix.tcgetattr(fd);
    termios.lflag.ECHO = enable;
    try std.posix.tcsetattr(fd, .NOW, termios);
}

fn setEcho(enable: bool) !void {
    switch (builtin.os.tag) {
        .windows => setEchoW(enable) catch {},
        else => setEchoL(enable) catch {},
    }
}
2 Likes