Skip to content

Commit

Permalink
Merge pull request #51 from TheWisePigeon/49-refactor-keys-creation
Browse files Browse the repository at this point in the history
Refactor keys creation
  • Loading branch information
joseph0x45 authored Jan 8, 2024
2 parents d3365d2 + 4e38118 commit 8a505bb
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 74 deletions.
4 changes: 2 additions & 2 deletions internal/handlers/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ func (h *AppHandler) GetHomePage(c *fiber.Ctx) error {
return c.Render("home", fiber.Map{})
}

func (h *AppHandler) GetKeyPage(c *fiber.Ctx) error {
return c.Render("keys", fiber.Map{})
func (h *AppHandler) GetKeysPage(c *fiber.Ctx) error {
return c.Render("keys", fiber.Map{}, "layouts/app")
}
46 changes: 17 additions & 29 deletions internal/handlers/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ package handlers
import (
"errors"
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/oklog/ulid/v2"
"log/slog"
"math/rand"
"time"
"visio/internal/store"
"visio/internal/types"
"visio/pkg"

"github.com/gofiber/fiber/v2"
"github.com/oklog/ulid/v2"
)

type KeyHandler struct {
Expand All @@ -31,70 +30,59 @@ func NewKeyHandler(keysStore *store.Keys, sessionsStore *store.Sessions, logger
func generateKey(length int) string {
const CHARACTER_POOL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-_=+:;'/?><|"
key := ""

for i := 0; i < length; i++ {
idx := rand.Intn(len(CHARACTER_POOL))
key += string(CHARACTER_POOL[idx])
}

return key
}

func (h *KeyHandler) CreateKey(c *fiber.Ctx) error {
currentUser, ok := c.Locals("currentUser").(*types.User)

if !ok {
err := errors.New("Error during currentUser type conversion")
h.logger.Error(err.Error())
return c.SendStatus(fiber.StatusUnauthorized)
}

const KEY_LIMIT = 3

// Check how many number of keys the user has already created
key_count, err := h.keys.CountByOwnerId(currentUser.Id)

fmt.Println("Key count", key_count)
if err != nil {
h.logger.Error(err.Error())
return c.SendStatus(fiber.StatusInternalServerError)
}

if key_count > KEY_LIMIT {
err := errors.New("Limit of keys exceeded")
h.logger.Error(err.Error())
return c.SendStatus(fiber.StatusForbidden)
}

// Generate prefix - ULID format
prefix := ulid.Make().String()

// Generate 23 characters long string - the key
key := generateKey(23)

// Hash the key
hashedKey, err := pkg.Hash(key)
if err != nil {
h.logger.Error(err.Error())
return c.SendStatus(fiber.StatusInternalServerError)
}

generatedKey := &types.Key{
KeyOwner: currentUser.Id,
Prefix: prefix,
KeyHash: hashedKey,
KeyCreationDate: time.Now().UTC(),
UserId: currentUser.Id,
Prefix: prefix,
KeyHash: hashedKey,
CreationDate: time.Now().UTC(),
}

_ = hashedKey

// Store key and prefix in DB
if err := h.keys.Insert(generatedKey); err != nil {
h.logger.Error(err.Error())
return c.SendStatus(fiber.StatusInternalServerError)
}

//Return key in format <prefix>.<key (unhased)> to user
finalKey := fmt.Sprintf("%s.%s", prefix, key)
return c.Send([]byte(finalKey))
err = c.JSON(
map[string]interface{}{
"data": map[string]string{
"key": finalKey,
},
},
)
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
return c.SendStatus(fiber.StatusCreated)
}
11 changes: 4 additions & 7 deletions internal/store/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package store

import (
"fmt"
"visio/internal/types"

"github.com/jmoiron/sqlx"
"visio/internal/types"
)

type Keys struct {
Expand All @@ -20,22 +19,20 @@ func NewKeysStore(db *sqlx.DB) *Keys {
func (k *Keys) Insert(key *types.Key) error {
_, err := k.db.NamedExec(
`
insert into keys(key_owner, prefix, key_hash, key_creation_date)
values (:key_owner, :prefix, :key_hash, :key_creation_date)
insert into keys(user_id, prefix, key_hash, creation_date)
values (:user_id, :prefix, :key_hash, :creation_date)
`,
key,
)

if err != nil {
return fmt.Errorf("Error while inserting new key: %w", err)
}

return nil
}

func (k *Keys) CountByOwnerId(ownerId string) (int, error) {
count := 0
err := k.db.QueryRowx("select count(*) from keys where key_owner=$1", ownerId).Scan(&count)
err := k.db.QueryRowx("select count(*) from keys where user_id=$1", ownerId).Scan(&count)
if err != nil {
return 0, fmt.Errorf("Error while counting keys by owner id: %w", err)
}
Expand Down
8 changes: 4 additions & 4 deletions internal/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package types
import "time"

type Key struct {
KeyOwner string `json:"key_owner" db:"key_owner"`
Prefix string `json:"prefix" db:"prefix"`
KeyHash string `json:"key_hash" db:"key_hash"`
KeyCreationDate time.Time `json:"key_creation_date" db:"key_creation_date"`
UserId string `json:"user_id" db:"user_id"`
Prefix string `json:"prefix" db:"prefix"`
KeyHash string `json:"key_hash" db:"key_hash"`
CreationDate time.Time `json:"creation_date" db:"creation_date"`
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func main() {
client.Get("/", appHandler.GetLandingPage)
client.Get("/auth", appHandler.GetAuthPage)
client.Get("/home", authMiddleware.CookieAuth, appHandler.GetHomePage)
client.Get("/manage-keys", appHandler.GetKeyPage)
client.Get("/keys", appHandler.GetKeysPage)

server := app.Group("/api")
server.Post("/auth", authHandler.Signup)
Expand Down
6 changes: 3 additions & 3 deletions schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ create table if not exists users (
);

create table if not exists keys (
key_owner text not null references users(id),
user_id text not null references users(id),
prefix text not null unique primary key,
key_hash text not null unique,
key_creation_date timestamp not null
)
creation_date timestamp not null
)
63 changes: 35 additions & 28 deletions views/keys.html
Original file line number Diff line number Diff line change
@@ -1,38 +1,45 @@
<!-- This is a dummy file for testing key functionality -->

<head>
<title>Key Auth</title>
<title>Visio | Keys</title>
</head>

<main x-data="init()">
<section class="p-12">
<button class="border bg-black text-white p-2 rounded-md w-32 text-center" @click="createKey"
type="button">Create
API key</button>
<button class="border p-2 rounded-md w-32 text-center">Revoke API key</button>
</section>
<!-- <div class="absolute"> -->
<!-- <h1>This is your key</h1> -->
<!-- </div> -->
<div class="w-full flex justify-between mt-5 items-baseline">
<h1 class="text-xl font-bold">Manage your API keys</h1>
<button x-bind:disabled="creating_key" @click="createKey" class="w-32 p-2 bg-black text-white rounded-md"
type="button">
<h1 x-show="!creating_key">New Key</h1>
<h1 x-show="creating_key">Creating...</h1>
</button>
</div>
</main>


<script>
function init() {
return {
createKey: async function () {
try {
console.log("Creating key")
const response = await fetch(
`/api/key`,
{
method: "POST",
headers: {
"Content-Type": "application/json"
}
}
)
} catch (err) {
console.log(err)
}
function init() {
return {
creating_key: false,
createKey: async function () {
creating_key = true
try {
console.log("Creating key")
const response = await fetch(
`/api/key`,
{
method: "POST",
headers: {
"Content-Type": "application/json"
}
}
)
creating_key = false
console.log(response.status)
} catch (err) {
alert("Something went wrong. Please retry or contact us")
console.log(err)
}
}
}
</script>
}
</script>
28 changes: 28 additions & 0 deletions views/layouts/app.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="" href="/public/output.css">
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
</head>

<body class="w-full h-screen ">
<main class="m-auto w-full p-2 lg:w-[50%] ">
<nav class="w-full flex justify-between items-baseline border-b-2 ">
<h1 class="text-2xl">VISIO</h1>
<div class="flex gap-5">
<a class="hover:underline" target="_blank" rel="noreferrer" href="https://github.com/TheWisePigeon/visio">
<h1>GitHub</h1>
</a>
<a class="hover:underline" target="_blank" rel="noreferrer" href="https://discord.gg/DsGc5EvQ">
<h1>Discord</h1>
</a>
</div>
</nav>
{{embed}}
</main>
</body>

</html>

0 comments on commit 8a505bb

Please sign in to comment.