refactor: rename email back to username

This commit is contained in:
Stavros
2025-01-26 18:29:30 +02:00
parent 708006decf
commit 989ea8f229
12 changed files with 58 additions and 58 deletions

View File

@@ -18,7 +18,7 @@ import (
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "tinyauth", Use: "tinyauth",
Short: "The simplest way to protect your apps with a login screen.", Short: "The simplest way to protect your apps with a login screen.",
Long: `Tinyauth is a simple authentication middleware that adds simple email/password login or OAuth with Google, Github and any generic OAuth provider to all of your docker apps.`, Long: `Tinyauth is a simple authentication middleware that adds simple username/password login or OAuth with Google, Github and any generic OAuth provider to all of your docker apps.`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
// Get config // Get config
log.Info().Msg("Parsing config") log.Info().Msg("Parsing config")
@@ -126,8 +126,8 @@ func init() {
rootCmd.Flags().String("address", "0.0.0.0", "Address to bind the server to.") rootCmd.Flags().String("address", "0.0.0.0", "Address to bind the server to.")
rootCmd.Flags().String("secret", "", "Secret to use for the cookie.") rootCmd.Flags().String("secret", "", "Secret to use for the cookie.")
rootCmd.Flags().String("app-url", "", "The tinyauth URL.") rootCmd.Flags().String("app-url", "", "The tinyauth URL.")
rootCmd.Flags().String("users", "", "Comma separated list of users in the format email:hash.") rootCmd.Flags().String("users", "", "Comma separated list of users in the format username:hash.")
rootCmd.Flags().String("users-file", "", "Path to a file containing users in the format email:hash.") rootCmd.Flags().String("users-file", "", "Path to a file containing users in the format username:hash.")
rootCmd.Flags().Bool("cookie-secure", false, "Send cookie over secure connection only.") rootCmd.Flags().Bool("cookie-secure", false, "Send cookie over secure connection only.")
rootCmd.Flags().String("github-client-id", "", "Github OAuth client ID.") rootCmd.Flags().String("github-client-id", "", "Github OAuth client ID.")
rootCmd.Flags().String("github-client-secret", "", "Github OAuth client secret.") rootCmd.Flags().String("github-client-secret", "", "Github OAuth client secret.")

View File

@@ -12,7 +12,7 @@ import (
) )
var interactive bool var interactive bool
var email string var username string
var password string var password string
var docker bool var docker bool
@@ -24,9 +24,9 @@ var CreateCmd = &cobra.Command{
if interactive { if interactive {
form := huh.NewForm( form := huh.NewForm(
huh.NewGroup( huh.NewGroup(
huh.NewInput().Title("Email").Value(&email).Validate((func(s string) error { huh.NewInput().Title("Username").Value(&username).Validate((func(s string) error {
if s == "" { if s == "" {
return errors.New("email cannot be empty") return errors.New("username cannot be empty")
} }
return nil return nil
})), })),
@@ -49,11 +49,11 @@ var CreateCmd = &cobra.Command{
} }
} }
if email == "" || password == "" { if username == "" || password == "" {
log.Error().Msg("Email and password cannot be empty") log.Error().Msg("Username and password cannot be empty")
} }
log.Info().Str("email", email).Str("password", password).Bool("docker", docker).Msg("Creating user") log.Info().Str("username", username).Str("password", password).Bool("docker", docker).Msg("Creating user")
passwordByte, passwordErr := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) passwordByte, passwordErr := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
@@ -67,13 +67,13 @@ var CreateCmd = &cobra.Command{
passwordString = strings.ReplaceAll(passwordString, "$", "$$") passwordString = strings.ReplaceAll(passwordString, "$", "$$")
} }
log.Info().Str("user", fmt.Sprintf("%s:%s", email, passwordString)).Msg("User created") log.Info().Str("user", fmt.Sprintf("%s:%s", username, passwordString)).Msg("User created")
}, },
} }
func init() { func init() {
CreateCmd.Flags().BoolVar(&interactive, "interactive", false, "Create a user interactively") CreateCmd.Flags().BoolVar(&interactive, "interactive", false, "Create a user interactively")
CreateCmd.Flags().BoolVar(&docker, "docker", false, "Format output for docker") CreateCmd.Flags().BoolVar(&docker, "docker", false, "Format output for docker")
CreateCmd.Flags().StringVar(&email, "email", "", "Email") CreateCmd.Flags().StringVar(&username, "username", "", "Username")
CreateCmd.Flags().StringVar(&password, "password", "", "Password") CreateCmd.Flags().StringVar(&password, "password", "", "Password")
} }

View File

@@ -11,7 +11,7 @@ import (
) )
var interactive bool var interactive bool
var email string var username string
var password string var password string
var docker bool var docker bool
var user string var user string
@@ -19,20 +19,20 @@ var user string
var VerifyCmd = &cobra.Command{ var VerifyCmd = &cobra.Command{
Use: "verify", Use: "verify",
Short: "Verify a user is set up correctly", Short: "Verify a user is set up correctly",
Long: `Verify a user is set up correctly meaning that it has a correct email and password.`, Long: `Verify a user is set up correctly meaning that it has a correct username and password.`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
if interactive { if interactive {
form := huh.NewForm( form := huh.NewForm(
huh.NewGroup( huh.NewGroup(
huh.NewInput().Title("User (email:hash)").Value(&user).Validate((func(s string) error { huh.NewInput().Title("User (username:hash)").Value(&user).Validate((func(s string) error {
if s == "" { if s == "" {
return errors.New("user cannot be empty") return errors.New("user cannot be empty")
} }
return nil return nil
})), })),
huh.NewInput().Title("Email").Value(&email).Validate((func(s string) error { huh.NewInput().Title("Username").Value(&username).Validate((func(s string) error {
if s == "" { if s == "" {
return errors.New("email cannot be empty") return errors.New("username cannot be empty")
} }
return nil return nil
})), })),
@@ -55,11 +55,11 @@ var VerifyCmd = &cobra.Command{
} }
} }
if email == "" || password == "" || user == "" { if username == "" || password == "" || user == "" {
log.Fatal().Msg("Email, password and user cannot be empty") log.Fatal().Msg("Username, password and user cannot be empty")
} }
log.Info().Str("user", user).Str("email", email).Str("password", password).Bool("docker", docker).Msg("Verifying user") log.Info().Str("user", user).Str("username", username).Str("password", password).Bool("docker", docker).Msg("Verifying user")
userSplit := strings.Split(user, ":") userSplit := strings.Split(user, ":")
@@ -73,8 +73,8 @@ var VerifyCmd = &cobra.Command{
verifyErr := bcrypt.CompareHashAndPassword([]byte(userSplit[1]), []byte(password)) verifyErr := bcrypt.CompareHashAndPassword([]byte(userSplit[1]), []byte(password))
if verifyErr != nil || email != userSplit[0] { if verifyErr != nil || username != userSplit[0] {
log.Fatal().Msg("Email or password incorrect") log.Fatal().Msg("Username or password incorrect")
} else { } else {
log.Info().Msg("Verification successful") log.Info().Msg("Verification successful")
} }
@@ -84,7 +84,7 @@ var VerifyCmd = &cobra.Command{
func init() { func init() {
VerifyCmd.Flags().BoolVarP(&interactive, "interactive", "i", false, "Create a user interactively") VerifyCmd.Flags().BoolVarP(&interactive, "interactive", "i", false, "Create a user interactively")
VerifyCmd.Flags().BoolVar(&docker, "docker", false, "Is the user formatted for docker?") VerifyCmd.Flags().BoolVar(&docker, "docker", false, "Is the user formatted for docker?")
VerifyCmd.Flags().StringVar(&email, "email", "", "Email") VerifyCmd.Flags().StringVar(&username, "username", "", "Username")
VerifyCmd.Flags().StringVar(&password, "password", "", "Password") VerifyCmd.Flags().StringVar(&password, "password", "", "Password")
VerifyCmd.Flags().StringVar(&user, "user", "", "Hash (user:hash combination)") VerifyCmd.Flags().StringVar(&user, "user", "", "Hash (username:hash combination)")
} }

View File

@@ -142,7 +142,7 @@ func (api *API) SetupRoutes() {
return return
} }
user := api.Auth.GetUser(login.Email) user := api.Auth.GetUser(login.Username)
if user == nil { if user == nil {
c.JSON(401, gin.H{ c.JSON(401, gin.H{
@@ -161,7 +161,7 @@ func (api *API) SetupRoutes() {
} }
session := sessions.Default(c) session := sessions.Default(c)
session.Set("tinyauth_sid", fmt.Sprintf("email:%s", login.Email)) session.Set("tinyauth_sid", fmt.Sprintf("username:%s", login.Username))
session.Save() session.Save()
c.JSON(200, gin.H{ c.JSON(200, gin.H{
@@ -199,7 +199,7 @@ func (api *API) SetupRoutes() {
c.JSON(200, gin.H{ c.JSON(200, gin.H{
"status": 200, "status": 200,
"message": "Unauthenticated", "message": "Unauthenticated",
"email": "", "username": "",
"isLoggedIn": false, "isLoggedIn": false,
"oauth": false, "oauth": false,
"provider": "", "provider": "",
@@ -212,7 +212,7 @@ func (api *API) SetupRoutes() {
c.JSON(200, gin.H{ c.JSON(200, gin.H{
"status": 200, "status": 200,
"message": "Authenticated", "message": "Authenticated",
"email": userContext.Email, "username": userContext.Username,
"isLoggedIn": userContext.IsLoggedIn, "isLoggedIn": userContext.IsLoggedIn,
"oauth": userContext.OAuth, "oauth": userContext.OAuth,
"provider": userContext.Provider, "provider": userContext.Provider,
@@ -306,7 +306,7 @@ func (api *API) SetupRoutes() {
if !api.Auth.EmailWhitelisted(email) { if !api.Auth.EmailWhitelisted(email) {
log.Warn().Str("email", email).Msg("Email not whitelisted") log.Warn().Str("email", email).Msg("Email not whitelisted")
unauthorizedQuery, unauthorizedQueryErr := query.Values(types.UnauthorizedQuery{ unauthorizedQuery, unauthorizedQueryErr := query.Values(types.UnauthorizedQuery{
Email: email, Username: email,
}) })
if handleApiError(c, "Failed to build query", unauthorizedQueryErr) { if handleApiError(c, "Failed to build query", unauthorizedQueryErr) {
return return

View File

@@ -18,9 +18,9 @@ type Auth struct {
OAuthWhitelist []string OAuthWhitelist []string
} }
func (auth *Auth) GetUser(email string) *types.User { func (auth *Auth) GetUser(username string) *types.User {
for _, user := range auth.Users { for _, user := range auth.Users {
if user.Email == email { if user.Username == username {
return &user return &user
} }
} }
@@ -28,7 +28,7 @@ func (auth *Auth) GetUser(email string) *types.User {
} }
func (auth *Auth) CheckPassword(user types.User, password string) bool { func (auth *Auth) CheckPassword(user types.User, password string) bool {
hashedPasswordErr := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) hashedPasswordErr := bcrypt.CompareHashAndPassword([]byte(user.Username), []byte(password))
return hashedPasswordErr == nil return hashedPasswordErr == nil
} }

View File

@@ -28,7 +28,7 @@ func (hooks *Hooks) UseUserContext(c *gin.Context) (types.UserContext, error) {
if sessionCookie == nil { if sessionCookie == nil {
return types.UserContext{ return types.UserContext{
Email: "", Username: "",
IsLoggedIn: false, IsLoggedIn: false,
OAuth: false, OAuth: false,
Provider: "", Provider: "",
@@ -39,7 +39,7 @@ func (hooks *Hooks) UseUserContext(c *gin.Context) (types.UserContext, error) {
if !dataOk { if !dataOk {
return types.UserContext{ return types.UserContext{
Email: "", Username: "",
IsLoggedIn: false, IsLoggedIn: false,
OAuth: false, OAuth: false,
Provider: "", Provider: "",
@@ -50,7 +50,7 @@ func (hooks *Hooks) UseUserContext(c *gin.Context) (types.UserContext, error) {
if len(split) != 2 { if len(split) != 2 {
return types.UserContext{ return types.UserContext{
Email: "", Username: "",
IsLoggedIn: false, IsLoggedIn: false,
OAuth: false, OAuth: false,
Provider: "", Provider: "",
@@ -60,18 +60,18 @@ func (hooks *Hooks) UseUserContext(c *gin.Context) (types.UserContext, error) {
sessionType := split[0] sessionType := split[0]
sessionValue := split[1] sessionValue := split[1]
if sessionType == "email" { if sessionType == "username" {
user := hooks.Auth.GetUser(sessionValue) user := hooks.Auth.GetUser(sessionValue)
if user == nil { if user == nil {
return types.UserContext{ return types.UserContext{
Email: "", Username: "",
IsLoggedIn: false, IsLoggedIn: false,
OAuth: false, OAuth: false,
Provider: "", Provider: "",
}, nil }, nil
} }
return types.UserContext{ return types.UserContext{
Email: sessionValue, Username: sessionValue,
IsLoggedIn: true, IsLoggedIn: true,
OAuth: false, OAuth: false,
Provider: "", Provider: "",
@@ -82,7 +82,7 @@ func (hooks *Hooks) UseUserContext(c *gin.Context) (types.UserContext, error) {
if provider == nil { if provider == nil {
return types.UserContext{ return types.UserContext{
Email: "", Username: "",
IsLoggedIn: false, IsLoggedIn: false,
OAuth: false, OAuth: false,
Provider: "", Provider: "",
@@ -93,7 +93,7 @@ func (hooks *Hooks) UseUserContext(c *gin.Context) (types.UserContext, error) {
session.Delete("tinyauth_sid") session.Delete("tinyauth_sid")
session.Save() session.Save()
return types.UserContext{ return types.UserContext{
Email: "", Username: "",
IsLoggedIn: false, IsLoggedIn: false,
OAuth: false, OAuth: false,
Provider: "", Provider: "",
@@ -101,7 +101,7 @@ func (hooks *Hooks) UseUserContext(c *gin.Context) (types.UserContext, error) {
} }
return types.UserContext{ return types.UserContext{
Email: sessionValue, Username: sessionValue,
IsLoggedIn: true, IsLoggedIn: true,
OAuth: true, OAuth: true,
Provider: sessionType, Provider: sessionType,

View File

@@ -7,12 +7,12 @@ type LoginQuery struct {
} }
type LoginRequest struct { type LoginRequest struct {
Email string `json:"email"` Username string `json:"username"`
Password string `json:"password"` Password string `json:"password"`
} }
type User struct { type User struct {
Email string Username string
Password string Password string
} }
@@ -42,7 +42,7 @@ type Config struct {
} }
type UserContext struct { type UserContext struct {
Email string Username string
IsLoggedIn bool IsLoggedIn bool
OAuth bool OAuth bool
Provider string Provider string
@@ -83,5 +83,5 @@ type OAuthProviders struct {
} }
type UnauthorizedQuery struct { type UnauthorizedQuery struct {
Email string `url:"email"` Username string `url:"username"`
} }

View File

@@ -22,7 +22,7 @@ func ParseUsers(users string) (types.Users, error) {
return types.Users{}, errors.New("invalid user format") return types.Users{}, errors.New("invalid user format")
} }
usersParsed = append(usersParsed, types.User{ usersParsed = append(usersParsed, types.User{
Email: userSplit[0], Username: userSplit[0],
Password: userSplit[1], Password: userSplit[1],
}) })
} }

View File

@@ -32,7 +32,7 @@ export const LoginPage = () => {
} }
const schema = z.object({ const schema = z.object({
email: z.string().email(), username: z.string(),
password: z.string(), password: z.string(),
}); });
@@ -41,7 +41,7 @@ export const LoginPage = () => {
const form = useForm({ const form = useForm({
mode: "uncontrolled", mode: "uncontrolled",
initialValues: { initialValues: {
email: "", username: "",
password: "", password: "",
}, },
validate: zodResolver(schema), validate: zodResolver(schema),
@@ -54,7 +54,7 @@ export const LoginPage = () => {
onError: () => { onError: () => {
notifications.show({ notifications.show({
title: "Failed to login", title: "Failed to login",
message: "Check your email and password", message: "Check your username and password",
color: "red", color: "red",
}); });
}, },
@@ -154,7 +154,7 @@ export const LoginPage = () => {
)} )}
</Grid> </Grid>
<Divider <Divider
label="Or continue with email" label="Or continue with password"
labelPosition="center" labelPosition="center"
my="lg" my="lg"
/> />
@@ -162,12 +162,12 @@ export const LoginPage = () => {
)} )}
<form onSubmit={form.onSubmit(handleSubmit)}> <form onSubmit={form.onSubmit(handleSubmit)}>
<TextInput <TextInput
label="Email" label="Username"
placeholder="user@example.com" placeholder="user@example.com"
required required
disabled={loginMutation.isLoading} disabled={loginMutation.isLoading}
key={form.key("email")} key={form.key("username")}
{...form.getInputProps("email")} {...form.getInputProps("username")}
/> />
<PasswordInput <PasswordInput
label="Password" label="Password"

View File

@@ -8,7 +8,7 @@ import { Layout } from "../components/layouts/layout";
import { capitalize } from "../utils/utils"; import { capitalize } from "../utils/utils";
export const LogoutPage = () => { export const LogoutPage = () => {
const { isLoggedIn, email, oauth, provider } = useUserContext(); const { isLoggedIn, username, oauth, provider } = useUserContext();
if (!isLoggedIn) { if (!isLoggedIn) {
return <Navigate to="/login" />; return <Navigate to="/login" />;
@@ -44,7 +44,7 @@ export const LogoutPage = () => {
Logout Logout
</Text> </Text>
<Text> <Text>
You are currently logged in as <Code>{email}</Code> You are currently logged in as <Code>{username}</Code>
{oauth && ` using ${capitalize(provider)}`}. Click the button below to {oauth && ` using ${capitalize(provider)}`}. Click the button below to
log out. log out.
</Text> </Text>

View File

@@ -6,7 +6,7 @@ import { Navigate } from "react-router";
export const UnauthorizedPage = () => { export const UnauthorizedPage = () => {
const queryString = window.location.search; const queryString = window.location.search;
const params = new URLSearchParams(queryString); const params = new URLSearchParams(queryString);
const email = params.get("email"); const username = params.get("email");
const { isLoggedIn } = useUserContext(); const { isLoggedIn } = useUserContext();
@@ -14,7 +14,7 @@ export const UnauthorizedPage = () => {
return <Navigate to="/" />; return <Navigate to="/" />;
} }
if (email === "null") { if (username === "null") {
return <Navigate to="/" />; return <Navigate to="/" />;
} }
@@ -25,7 +25,7 @@ export const UnauthorizedPage = () => {
Unauthorized Unauthorized
</Text> </Text>
<Text> <Text>
The user with email address <Code>{email}</Code> is not authorized to The user with username <Code>{username}</Code> is not authorized to
login. login.
</Text> </Text>
<Button <Button

View File

@@ -2,7 +2,7 @@ import { z } from "zod";
export const userContextSchema = z.object({ export const userContextSchema = z.object({
isLoggedIn: z.boolean(), isLoggedIn: z.boolean(),
email: z.string(), username: z.string(),
oauth: z.boolean(), oauth: z.boolean(),
provider: z.string(), provider: z.string(),
configuredProviders: z.array(z.string()), configuredProviders: z.array(z.string()),