Skip to content

Commit

Permalink
add authentication with pocketbase (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
Inveracity authored Jul 7, 2023
1 parent 9a42b27 commit 42b7580
Show file tree
Hide file tree
Showing 37 changed files with 666 additions and 203 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ docker
frontend/node_modules
frontend/.svelte-kit
frontend/build
frontend/.env
.eslintignore
.eslintrc.cjs
.prettierrc
Expand Down
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,19 @@
clean:
rm -rf relay/internal/proto
rm -rf frontend/src/proto
rm -rf api/proto

.PHONY: proto
proto: clean
buf generate

.PHONY: build
build:
docker build -t inveracity/chat-relay:latest -f docker/relay.dockerfile .
docker push inveracity/chat-relay:latest
docker build -t inveracity/chat-frontend:latest -f docker/frontend.dockerfile .
docker push inveracity/chat-frontend:latest

.PHONY: deploy
deploy:
nomad job run nomad/relay.nomad
nomad job run nomad/frontend.nomad
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This project consists of 5 infrastructure components
- NATS: for queueing notifications that need to be relayed
- Redis: caches messages
- Relay (golang): Picks up messages from the queue and forwards them to a gRPC stream to the frontend
- Pocketbase: For user authentication
- Frontend (svelte & typecript): For sending notifications via the API and recieving notifications via the Relay.

## Documentation
Expand All @@ -36,8 +37,12 @@ In your hosts file set:

```plaintext
127.0.0.1 frontend.docker.localhost
127.0.0.1 relay.docker.localhost
127.0.0.1 api.docker.localhost
```

After running `docker compose up`, <http://frontend.docker.localhost> should now be available via Traefik.

## Quickstart

```sh
docker compose up --build
```
35 changes: 31 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ services:
relay:
depends_on:
- nats
#- redis
- redis
container_name: relay
build:
context: .
Expand All @@ -40,17 +40,24 @@ services:
- "50051:50051"
labels:
- "traefik.enable=true"
- "traefik.http.routers.relay.rule=Host(`relay.docker.localhost`)"
- "traefik.http.routers.relay.rule=Host(`frontend.docker.localhost`) && PathPrefix(`/relay/proto.chat.v1.ChatService`)"
- "traefik.http.services.relay.loadbalancer.server.scheme=h2c"
# Middleware
- "traefik.http.middlewares.relay-grpc.grpcWeb.allowOrigins=*"
- "traefik.http.routers.relay.middlewares=relay-grpc"
- "traefik.http.middlewares.relay-stripprefix.stripprefix.prefixes=/relay"
- "traefik.http.middlewares.relay-headers.headers.accesscontrolalloworiginlist=*"
- "traefik.http.routers.relay.middlewares=relay-grpc,relay-headers,relay-stripprefix"
environment:
- PB_USER=admin@localhost.com
- PB_PASS=abcdefghijkl

frontend:
container_name: frontend
depends_on:
- nats
#- redis
- redis
- relay
- pocketbase
build:
context: .
dockerfile: docker/frontend.dockerfile
Expand All @@ -60,3 +67,23 @@ services:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`frontend.docker.localhost`)"
- "traefik.http.services.frontend.loadbalancer.server.scheme=http"
environment:
- PUBLIC_POCKETBASE_URL=http://frontend.docker.localhost/pocketbase
- PUBLIC_RELAY_URL=http://frontend.docker.localhost/relay

pocketbase:
container_name: pocketbase
image: inveracity/pocketbase:latest
build:
context: .
dockerfile: docker/pocketbase.dockerfile
ports:
- 8090:8090
# volumes:
# - ./pb_data:/pb_data
labels:
- "traefik.enable=true"
- "traefik.http.routers.pocketbase.rule=Host(`frontend.docker.localhost`) && PathPrefix(`/pocketbase`)"
- "traefik.http.services.pocketbase.loadbalancer.server.scheme=http"
- "traefik.http.routers.pocketbase.middlewares=pocketbase-stripprefix"
- "traefik.http.middlewares.pocketbase-stripprefix.stripprefix.prefixes=/pocketbase"
8 changes: 0 additions & 8 deletions docker/api.dockerfile

This file was deleted.

12 changes: 6 additions & 6 deletions docker/frontend.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ ENV HOST=0.0.0.0
EXPOSE 3000
CMD ["node", "build/index.js"]

# FROM node:20-alpine3.18
FROM node:20-alpine3.18

# WORKDIR /app
# COPY --from=build /app .
WORKDIR /app
COPY --from=build /app .


# ENV HOST=0.0.0.0
# EXPOSE 3000
# CMD ["node","build/index.js"]
ENV HOST=0.0.0.0
EXPOSE 3000
CMD ["node","build/index.js"]
15 changes: 15 additions & 0 deletions docker/pocketbase.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM alpine:latest

ARG PB_VERSION=0.16.7

RUN apk add --no-cache \
unzip \
ca-certificates

# download and unzip PocketBase
ADD https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip /tmp/pb.zip
RUN unzip /tmp/pb.zip -d /pb/

EXPOSE 8090

CMD [ "/pb/pocketbase", "serve", "--http=0.0.0.0:8090" ]
38 changes: 22 additions & 16 deletions docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,35 @@ Whenever a user subscribes to realtime notifications, it creates a queue in NATS
sequenceDiagram
autonumber
actor Alice
actor Bob
participant Relay
participant Nats
participant Redis
participant API
actor Bob
participant PocketBase
participant Nats
Bob ->>+ API : Sends msg to "channel1"
API ->> Redis : Cache message in Redis
API ->>- Nats : Publish msg to "channel1"
Note over Nats : Since there are no subscribers the msg is dropped
Alice ->>+ Relay : Subscribe to "channel1"
Relay ->>+ Redis : Get "channel1" history from last timestamp
Redis ->>- Relay : Bob's message
Relay ->> Alice : Bob's message arrives at Alice
Relay ->>- Nats : Subscribe to "channel1"
Relay ->> Alice : Open server stream
Alice ->> PocketBase : Authenticate
Bob ->> PocketBase : Authenticate
Bob ->>+ Relay : Sends msg to "channel1"
Relay ->>+ PocketBase : Verify Token
PocketBase ->>- Relay : OK
Relay ->> Redis : Cache message in Redis
Relay ->>- Nats : Publish msg to "channel1"
Note over Nats : Since there are no subscribers the msg is dropped
Alice ->>+ Relay : Subscribe to "channel1"
Relay ->>+ PocketBase : Verify Token
PocketBase ->>- Relay : OK
Relay ->>+ Redis : Get "channel1" history from last timestamp
Redis ->>- Relay : Bob's message
Relay ->> Alice : Bob's message arrives at Alice
Relay ->>- Nats : Subscribe to "channel1"
Relay ->> Alice : Open server stream
loop Server Stream
Nats -->+ Relay : Subscribe
Bob ->> API : New message
API ->> Redis : Cache
API ->> Nats : Publish
Bob ->> Relay : New message
Relay ->> Redis : Cache
Relay ->> Nats : Publish
Nats -->> Relay : Msg
Note over Relay : Nats -> gRPC
Relay -->> Alice : gRPC server stream
Expand Down
2 changes: 2 additions & 0 deletions frontend/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PUBLIC_POCKETBASE_URL="http://frontend.docker.localhost/pocketbase"
PUBLIC_RELAY_URL="http://frontend.docker.localhost/relay"
1 change: 1 addition & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ node_modules
/build
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
!.env
5 changes: 5 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"@sveltejs/adapter-node": "^1.3.0",
"@types/luxon": "^3.3.0",
"luxon": "^3.3.0",
"pocketbase": "^0.15.2",
"svelte-loading-spinners": "^0.3.4",
"svelte-local-storage-store": "^0.5.0"
}
}
}
3 changes: 2 additions & 1 deletion frontend/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ body {
height: 100vh;
margin: 0;
display: flex;
flex-direction: row;
flex-direction: column;
max-height: 100vh;
}

Expand All @@ -36,6 +36,7 @@ a:-webkit-any-link {
flex-direction: column;
min-height: 0;
}

.row {
flex-grow: 1;
display: flex;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
<div style="display: contents">%sveltekit.body%</div>
</body>

</html>
</html>
31 changes: 0 additions & 31 deletions frontend/src/components/Controls.svelte

This file was deleted.

17 changes: 11 additions & 6 deletions frontend/src/components/Input.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script lang="ts">
import { channel } from '../stores/channel';
import { username } from '../stores/username';
import { currentUser } from '$lib/pocketbase';
import { status } from '../stores/status';
import { SendMessage } from '../grpc';
import { SendMessage } from '../lib/grpc';
import type { OutgoingMessage } from '../types';
let message = '';
Expand All @@ -11,18 +11,23 @@
e.preventDefault();
let msg: OutgoingMessage = {
channelId: $channel,
userId: $username,
text: message,
userId: $currentUser?.username,
text: message
};
SendMessage(msg);
message = '';
}
};
</script>

<div class="userInput">
<textarea id="userinput" placeholder={$status === "connected" ? "Message" : "disconnected" } bind:value={message} on:keypress={onKeyPress} disabled={$status !== "connected"} />
<textarea
id="userinput"
placeholder={$status === 'connected' ? 'Message' : 'disconnected'}
bind:value={message}
on:keypress={onKeyPress}
disabled={$status !== 'connected'}
/>
</div>

<style>
Expand Down
43 changes: 43 additions & 0 deletions frontend/src/components/Login.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script lang="ts">
import { currentUser, pb } from '$lib/pocketbase';
import { server } from '../stores/server';
import { Connect, Disconnect } from '../lib/grpc';
let password = '';
let username = '';
async function login() {
await pb.collection('users').authWithPassword(username, password);
await Connect($server, username, '0');
}
function logout() {
pb.authStore.clear();
Disconnect();
}
</script>

<div class="login">
{#if $currentUser}
<p class="padding">Signed in as {$currentUser.username}</p>
<button class="padding" on:click={logout}> Logout </button>
{:else}
<form class="padding" on:submit|preventDefault>
<input type="text" bind:value={username} placeholder="Email" />
<input type="password" bind:value={password} placeholder="Password" />
<input type="text" bind:value={$server} />
<button on:click={login}> Login </button>
</form>
{/if}
</div>

<style>
.login {
display: flex;
flex-direction: row;
align-items: center;
}
.padding {
padding: 10px;
}
</style>
Loading

0 comments on commit 42b7580

Please sign in to comment.