diff auth/hash_password.c @ 264:04fee26ecce0

add authenticated JRPG conversation platform Add reusable auth/session storage, owned conversation recovery, guest quotas, admin workflows, URL-routed conversation UI, mobile frame support, and parallel browser acceptance. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Fri, 07 Aug 2026 07:34:12 -0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/auth/hash_password.c	Fri Aug 07 07:34:12 2026 -0700
@@ -0,0 +1,111 @@
+#include "auth/auth_crypto.h"
+
+#include <openssl/crypto.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#define PW_MAX AUTH_CRYPTO_PASSWORD_MAX_BYTES
+
+static int read_password(int fd, char *buf, size_t capacity)
+{
+  size_t len = 0;
+  int too_long = 0;
+  for (;;)
+  {
+    unsigned char c;
+    int r = (int)read(fd, &c, 1);
+    if (r < 0)
+      return -1;
+    if (r == 0)
+      break;
+    if (c == '\n' || c == '\r')
+      break;
+    if (len + 1 >= capacity)
+    {
+      too_long = 1;
+      continue;
+    }
+    buf[len++] = (char)c;
+  }
+  buf[len] = '\0';
+  return too_long ? -2 : (int)len;
+}
+
+int main(int argc, char **argv)
+{
+  (void)argc;
+  (void)argv;
+
+  int fd = STDIN_FILENO;
+  int is_tty = isatty(fd);
+  struct termios old_term;
+  struct termios new_term;
+  int restored = 0;
+
+  if (is_tty)
+  {
+    if (tcgetattr(fd, &old_term) != 0)
+    {
+      fprintf(stderr, "hash_password: failed to get terminal attributes\n");
+      return 1;
+    }
+    new_term = old_term;
+    new_term.c_lflag &= (tcflag_t)~(ECHO | ECHOE | ECHOK | ECHONL);
+    new_term.c_lflag |= ICANON;
+    if (tcsetattr(fd, TCSAFLUSH, &new_term) != 0)
+    {
+      fprintf(stderr, "hash_password: failed to disable echo\n");
+      return 1;
+    }
+    restored = 1;
+    fprintf(stderr, "Password: ");
+    fflush(stderr);
+  }
+
+  char pw[PW_MAX + 1];
+  memset(pw, 0, sizeof(pw));
+  int n = read_password(fd, pw, sizeof(pw));
+
+  if (restored)
+  {
+    tcsetattr(fd, TCSAFLUSH, &old_term);
+    fprintf(stderr, "\n");
+  }
+
+  if (n == -2)
+  {
+    fprintf(stderr, "hash_password: %s\n",
+            Auth_Crypto_Result_String(AUTH_CRYPTO_PASSWORD_TOO_LONG));
+    OPENSSL_cleanse(pw, sizeof(pw));
+    return 1;
+  }
+  if (n < 0)
+  {
+    fprintf(stderr, "hash_password: read error\n");
+    OPENSSL_cleanse(pw, sizeof(pw));
+    return 1;
+  }
+  if (n == 0)
+  {
+    fprintf(stderr, "hash_password: empty password\n");
+    OPENSSL_cleanse(pw, sizeof(pw));
+    return 1;
+  }
+
+  char encoded_hash[AUTH_CRYPTO_PASSWORD_HASH_ENCODED_SIZE];
+  Auth_Crypto_Result result =
+      Auth_Crypto_Password_Hash(pw, encoded_hash, sizeof(encoded_hash));
+  OPENSSL_cleanse(pw, sizeof(pw));
+
+  if (result != AUTH_CRYPTO_OK)
+  {
+    fprintf(stderr, "hash_password: %s\n", Auth_Crypto_Result_String(result));
+    return 1;
+  }
+
+  puts(encoded_hash);
+  return 0;
+}