Skip to content

Commit

Permalink
feat: endpoint to get a key by id
Browse files Browse the repository at this point in the history
  • Loading branch information
chronark committed Jul 21, 2023
1 parent d60a0b8 commit b6707ab
Show file tree
Hide file tree
Showing 42 changed files with 1,095 additions and 844 deletions.
98 changes: 98 additions & 0 deletions apps/api/pkg/server/key_get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package server

import (
"errors"
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/unkeyed/unkey/apps/api/pkg/database"
"net/http"
)

type GetKeyRequest struct {
KeyId string `validate:"required"`
}

type GetKeyResponse = keyResponse

func (s *Server) getKey(c *fiber.Ctx) error {
ctx, span := s.tracer.Start(c.UserContext(), "server.getKey")
defer span.End()
req := GetKeyRequest{
KeyId: c.Params("keyId"),
}

err := s.validator.Struct(req)
if err != nil {
return c.Status(http.StatusBadRequest).JSON(ErrorResponse{
Code: BAD_REQUEST,
Error: fmt.Sprintf("unable to validate request: %s", err.Error()),
})
}

authHash, err := getKeyHash(c.Get("Authorization"))
if err != nil {
return err
}

authKey, err := s.db.GetKeyByHash(ctx, authHash)
if err != nil {
return c.Status(http.StatusInternalServerError).JSON(ErrorResponse{
Code: INTERNAL_SERVER_ERROR,
Error: fmt.Sprintf("unable to find key: %s", err.Error()),
})
}

if authKey.ForWorkspaceId == "" {
return c.Status(http.StatusBadRequest).JSON(ErrorResponse{
Code: BAD_REQUEST,
Error: "wrong key type",
})
}

key, err := s.db.GetKeyById(ctx, req.KeyId)
if err != nil {
if errors.Is(err, database.ErrNotFound) {
return c.Status(http.StatusNotFound).JSON(ErrorResponse{
Code: NOT_FOUND,
Error: fmt.Sprintf("unable to find key: %s", req.KeyId),
})
}
return c.Status(http.StatusInternalServerError).JSON(ErrorResponse{
Code: INTERNAL_SERVER_ERROR,
Error: fmt.Sprintf("unable to find key: %s", err.Error()),
})
}
if key.WorkspaceId != authKey.ForWorkspaceId {
return c.Status(http.StatusUnauthorized).JSON(ErrorResponse{
Code: UNAUTHORIZED,
Error: "access to workspace denied",
})
}

res := GetKeyResponse{
Id: key.Id,
ApiId: key.ApiId,
WorkspaceId: key.WorkspaceId,
Start: key.Start,
OwnerId: key.OwnerId,
Meta: key.Meta,
CreatedAt: key.CreatedAt.UnixMilli(),
ForWorkspaceId: key.ForWorkspaceId,
}
if !key.Expires.IsZero() {
res.Expires = key.Expires.UnixMilli()
}
if key.Ratelimit != nil {
res.Ratelimit = &ratelimitSettng{
Type: key.Ratelimit.Type,
Limit: key.Ratelimit.Limit,
RefillRate: key.Ratelimit.RefillRate,
RefillInterval: key.Ratelimit.RefillInterval,
}
}
if key.Remaining.Enabled {
res.Remaining = &key.Remaining.Remaining
}

return c.JSON(res)
}
71 changes: 71 additions & 0 deletions apps/api/pkg/server/key_get_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package server

import (
"context"
"encoding/json"
"fmt"
"io"
"net/http/httptest"
"os"
"testing"
"time"

"github.com/stretchr/testify/require"
"github.com/unkeyed/unkey/apps/api/pkg/cache"
"github.com/unkeyed/unkey/apps/api/pkg/database"
"github.com/unkeyed/unkey/apps/api/pkg/entities"
"github.com/unkeyed/unkey/apps/api/pkg/hash"
"github.com/unkeyed/unkey/apps/api/pkg/logging"
"github.com/unkeyed/unkey/apps/api/pkg/testutil"
"github.com/unkeyed/unkey/apps/api/pkg/tracing"
"github.com/unkeyed/unkey/apps/api/pkg/uid"
)

func KeyGetKey_Simple(t *testing.T) {
ctx := context.Background()
resources := testutil.SetupResources(t)

db, err := database.New(database.Config{
Logger: logging.NewNoopLogger(),

PrimaryUs: os.Getenv("DATABASE_DSN"),
})
require.NoError(t, err)

srv := New(Config{
Logger: logging.NewNoopLogger(),
KeyCache: cache.NewNoopCache[entities.Key](),
ApiCache: cache.NewNoopCache[entities.Api](),
Database: db,
Tracer: tracing.NewNoop(),
})

key := entities.Key{
Id: uid.Key(),
ApiId: resources.UserApi.Id,
WorkspaceId: resources.UserWorkspace.Id,
Hash: hash.Sha256(uid.New(16, "test")),
CreatedAt: time.Now(),
}
err = db.CreateKey(ctx, key)
require.NoError(t, err)

req := httptest.NewRequest("GET", fmt.Sprintf("/v1/keys/%s", key.Id), nil)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", resources.UnkeyKey))

res, err := srv.app.Test(req)
require.NoError(t, err)
defer res.Body.Close()

body, err := io.ReadAll(res.Body)
require.NoError(t, err)

require.Equal(t, 200, res.StatusCode)

successResponse := GetKeyResponse{}
err = json.Unmarshal(body, &successResponse)
require.NoError(t, err)

require.Equal(t, key, successResponse)

}
10 changes: 0 additions & 10 deletions apps/api/pkg/server/key_update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ func TestUpdateKey_UpdateAll(t *testing.T) {
require.NoError(t, err)
defer res.Body.Close()



require.Equal(t, res.StatusCode, 200)

found, err := db.GetKeyById(ctx, key.Id)
Expand Down Expand Up @@ -133,8 +131,6 @@ func TestUpdateKey_UpdateOnlyRatelimit(t *testing.T) {
require.NoError(t, err)
defer res.Body.Close()



require.Equal(t, res.StatusCode, 200)

found, err := db.GetKeyById(ctx, key.Id)
Expand Down Expand Up @@ -192,8 +188,6 @@ func TestUpdateKey_DeleteExpires(t *testing.T) {
require.NoError(t, err)
defer res.Body.Close()



require.Equal(t, res.StatusCode, 200)

found, err := db.GetKeyById(ctx, key.Id)
Expand Down Expand Up @@ -248,8 +242,6 @@ func TestUpdateKey_DeleteRemaining(t *testing.T) {
require.NoError(t, err)
defer res.Body.Close()



require.Equal(t, res.StatusCode, 200)

found, err := db.GetKeyById(ctx, key.Id)
Expand Down Expand Up @@ -305,8 +297,6 @@ func TestUpdateKey_UpdateShouldNotAffectUndefinedFields(t *testing.T) {
require.NoError(t, err)
defer res.Body.Close()



require.Equal(t, res.StatusCode, 200)

found, err := db.GetKeyById(ctx, key.Id)
Expand Down
3 changes: 2 additions & 1 deletion apps/api/pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,9 @@ func New(config Config) *Server {
s.app.Post("/v1/internal/rootkeys", s.createRootKey)

s.app.Post("/v1/keys", s.createKey)
s.app.Delete("/v1/keys/:keyId", s.deleteKey)
s.app.Get("/v1/keys/:keyId", s.getKey)
s.app.Put("/v1/keys/:keyId", s.updateKey)
s.app.Delete("/v1/keys/:keyId", s.deleteKey)
s.app.Post("/v1/keys/verify", s.verifyKey)

s.app.Get("/v1/apis/:apiId", s.getApi)
Expand Down
83 changes: 44 additions & 39 deletions apps/web/app/(landing)/about/page.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,58 @@
import Image from 'next/image'
import { Border } from '@/components/landing-components/border'
import { Container } from '@/components/landing-components/container'
import { FadeIn, FadeInStagger } from '@/components/landing-components/fade-in'
import { GridList, GridListItem } from '@/components/landing-components/grid-list'
import { PageIntro } from '@/components/landing-components/page-intro'
import { PageLinks } from '@/components/landing-components/page-links'
import { SectionIntro } from '@/components/landing-components/section-intro'
import { allPosts } from '@/.contentlayer/generated'
import imageJamesPerkins from '@/images/team/james.jpg'
import imageAndreas from '@/images/team/andreas.jpeg'
import Image from "next/image";
import { Border } from "@/components/landing-components/border";
import { Container } from "@/components/landing-components/container";
import { FadeIn, FadeInStagger } from "@/components/landing-components/fade-in";
import { GridList, GridListItem } from "@/components/landing-components/grid-list";
import { PageIntro } from "@/components/landing-components/page-intro";
import { PageLinks } from "@/components/landing-components/page-links";
import { SectionIntro } from "@/components/landing-components/section-intro";
import { allPosts } from "@/.contentlayer/generated";
import imageJamesPerkins from "@/images/team/james.jpg";
import imageAndreas from "@/images/team/andreas.jpeg";
function AboutUnkey() {
return (
<div className="mt-24 rounded-4xl bg-neutral-950 py-24 sm:mt-32 lg:mt-40 lg:py-32 ">
<SectionIntro
eyebrow=""
title="What is Unkey?"
invert
>
</SectionIntro>
<SectionIntro eyebrow="" title="What is Unkey?" invert></SectionIntro>
<Container className="mt-16">
<GridList>
<GridListItem title="Globally Founded, Globally Remote" invert>
We are globally remote and were founded that way too. We believe that the best talent is not always in the same place and that we can build a better product by hiring the best talent, no matter where they are.
We are globally remote and were founded that way too. We believe that the best talent is
not always in the same place and that we can build a better product by hiring the best
talent, no matter where they are.
</GridListItem>
<GridListItem title="Builders, Innovators" invert>
We are serial builders who love to innovate. We are always looking for new ways to improve our product and our community. If we aren&apos;t working on Unkey, we are probably learning about something new.
We are serial builders who love to innovate. We are always looking for new ways to
improve our product and our community. If we aren&apos;t working on Unkey, we are
probably learning about something new.
</GridListItem>
<GridListItem title="Open Source" invert>
Unkey is a fully open source project, we believe that open source leads to better products and better communities. We are committed to building a great open source community around Unkey and providing the ability to self host for those who want it.
Unkey is a fully open source project, we believe that open source leads to better
products and better communities. We are committed to building a great open source
community around Unkey and providing the ability to self host for those who want it.
</GridListItem>
</GridList>
</Container>
</div>
)
);
}

const team = [
{
title: 'Team',
title: "Team",
people: [
{
name: 'James Perkins',
role: 'Co-Founder / CEO',
name: "James Perkins",
role: "Co-Founder / CEO",
image: { src: imageJamesPerkins },
},
{
name: 'Andreas Thomas',
role: 'Co-Founder / CTO',
name: "Andreas Thomas",
role: "Co-Founder / CTO",
image: { src: imageAndreas },
},
],
},
]
];

function Team() {
return (
Expand Down Expand Up @@ -84,9 +85,7 @@ function Team() {
<p className="font-display text-base/6 font-semibold tracking-wide text-white">
{person.name}
</p>
<p className="mt-2 text-sm text-white">
{person.role}
</p>
<p className="mt-2 text-sm text-white">{person.role}</p>
</div>
</div>
</FadeIn>
Expand All @@ -99,31 +98,37 @@ function Team() {
))}
</div>
</Container>
)
);
}

export const metadata = {
title: 'About Us',
title: "About Us",
description:
'Unkey is a fully open source project, we believe that open source leads to better products and better communities. We are committed to building a great open source community around Unkey and providing the ability to self host for those who want it.',
}
"Unkey is a fully open source project, we believe that open source leads to better products and better communities. We are committed to building a great open source community around Unkey and providing the ability to self host for those who want it.",
};

export default async function About() {
const blogArticles = allPosts.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()).slice(0,2);
const blogArticles = allPosts
.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime())
.slice(0, 2);
return (
<>
<PageIntro eyebrow="" title="About us">
<p>
Unkey is a fully open source project, we believe that open source leads to better products and better communities. We are committed to building a great open source community around Unkey and providing the ability to self host for those who want it.
Unkey is a fully open source project, we believe that open source leads to better products
and better communities. We are committed to building a great open source community around
Unkey and providing the ability to self host for those who want it.
</p>
<div className="mt-10 max-w-2xl space-y-6 text-base">
<p>
Unkey was started by James Perkins and Andreas Thomas in 2023. We are a small team of serial builders who love to innovate. We are always looking for new ways to improve our product and our community. If we aren&apos;t working on Unkey, we are probably learning about something new.
Unkey was started by James Perkins and Andreas Thomas in 2023. We are a small team of
serial builders who love to innovate. We are always looking for new ways to improve our
product and our community. If we aren&apos;t working on Unkey, we are probably learning
about something new.
</p>
</div>
</PageIntro>


<AboutUnkey />

<Team />
Expand All @@ -135,5 +140,5 @@ export default async function About() {
pages={blogArticles}
/>
</>
)
);
}
Loading

0 comments on commit b6707ab

Please sign in to comment.