Skip to content

Commit

Permalink
Merge pull request #151 from AmazeeLabs/lagoon-SLB-204
Browse files Browse the repository at this point in the history
SLB-204: token-based decap authentication
  • Loading branch information
pmelab authored Mar 22, 2024
2 parents 6bfca47 + 3862593 commit 2aefbe9
Show file tree
Hide file tree
Showing 56 changed files with 4,632 additions and 2,241 deletions.
2 changes: 1 addition & 1 deletion .idea/prettier.xml

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

8 changes: 4 additions & 4 deletions apps/decap/data/page/decap-example.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
de:
path: /de/decap-example
title: Decap Beispiel!
title: Decap Beispiel
teaserImage: /apps/decap/media/landscape.jpg
hero:
headline: Decap Beispiel
headline: Decap Beispiel!
lead: Diese Seite wurde mit Decap CMS erstellt
image: /apps/decap/media/landscape.jpg
content:
Expand All @@ -12,10 +12,10 @@ de:
en:
id: BTPzQnq79fWNOF1dFmESP
path: /en/decap-example
title: Decap example!
title: Decap example (UPDATE)
teaserImage: /apps/decap/media/landscape.jpg
hero:
headline: Decap Example
headline: Decap Example!
lead: This page was created with Decap CMS
image: /apps/decap/media/landscape.jpg
content:
Expand Down
5 changes: 2 additions & 3 deletions apps/decap/index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Decap</title>
<script type="text/javascript" src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
</head>
<body>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
</html>
1 change: 1 addition & 0 deletions apps/decap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@amazeelabs/decap-cms-backend-token-auth": "workspace:*",
"@amazeelabs/gatsby-source-silverback": "^1.13.7",
"@types/node": "^18",
"@types/react": "^18.2.46",
Expand Down
22 changes: 14 additions & 8 deletions apps/decap/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TokenAuthBackend } from '@amazeelabs/decap-cms-backend-token-auth/backend';
import {
Locale,
PreviewDecapPageQuery,
Expand All @@ -18,26 +19,31 @@ const default_locale = locales.includes('en') ? 'en' : locales[0];

CMS.registerPreviewStyle(css, { raw: true });
CMS.registerWidget('uuid', UuidWidget);
CMS.registerBackend('token-auth', TokenAuthBackend);

CMS.init({
config: {
publish_mode: 'simple',
media_folder: 'apps/decap/media',
// @ts-ignore
backend: import.meta.env.DEV
? // In development, use the in-memory backend.
{
? {
// In development, use the in-memory backend.
name: 'test-repo',
}
: window.location.hostname === 'localhost'
? // On localhost, use the proxy backend.
{
? {
// On localhost, use the proxy backend that writes to files.
name: 'proxy',
proxy_url: 'http://localhost:8081/api/v1',
}
: // Otherwise, its production. Use the Git Gateway backend.
{
name: 'git-gateway',
branch: 'release',
: {
// Otherwise, its production. Use the token auth backend.
name: 'token-auth',
api_root: '/admin/_github',
repo: 'AmazeeLabs/silverback-template',
// TODO: set to "prod" before merge
branch: 'lagoon-SLB-204',
},
i18n: {
structure: 'single_file',
Expand Down
4 changes: 2 additions & 2 deletions apps/decap/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
"pipeline": {
"prep:vite": {
"dependsOn": ["^prep"],
"inputs": ["src/**", "vite.config.js"],
"inputs": ["src/**", "vite.config.ts", "index.html"],
"outputs": ["dist/**"]
},
"prep:scripts": {
"dependsOn": ["^prep"],
"inputs": ["src/**", "tsup.config.js"],
"inputs": ["src/**", "tsup.config.ts"],
"outputs": ["build/**"]
},
"prep": {
Expand Down
7 changes: 7 additions & 0 deletions apps/website/gatsby-node.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ export const createPages = async ({ actions }) => {
});
});

// Redirect Decap Github requests to the proxy function.
actions.createRedirect({
fromPath: '/admin/_github/*',
toPath: `/.netlify/functions/github-proxy`,
statusCode: 200,
});

// Any unhandled requests are handed to strangler, which will try to pass
// them to all registered legacy systems and return 404 if none of them
// respond.
Expand Down
12 changes: 11 additions & 1 deletion apps/website/netlify.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
[dev]
autoLaunch = false

[functions]
directory = "netlify/functions"

[build]
edge_functions = "netlify/edge-functions"

[functions.strangler]
included_files = ["public/404.html"]

[[edge_functions]]
path = "/"
function = "homepage-redirect"
function = "homepage-redirect"

[[edge_functions]]
path = "/admin/_github/*"
function = "github-proxy-auth"
34 changes: 34 additions & 0 deletions apps/website/netlify/edge-functions/github-proxy-auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { Context } from '@netlify/edge-functions';

// For some reason pnpm package imports break in edge handlers.
import {
JwtEncoder,
PostmarkEmailBackend,
TokenAuthHandler,
} from '../../node_modules/@amazeelabs/token-auth-middleware/build/index.js';

export default async (request: Request, context: Context) => {
if (
!(Netlify.env.has('JWT_SECRET') && Netlify.env.has('POSTMARK_API_TOKEN'))
) {
throw new Error(
'Missing environment variables JWT_SECRET and POSTMARK_API_TOKEN.',
);
}

const encoder = new JwtEncoder(Netlify.env.get('JWT_SECRET') as string);
const backend = new PostmarkEmailBackend(
{
// Grant access to everybody @amazeelabs.com.
'*@amazeelabs.com': '*',
},
'[email protected]',
Netlify.env.get('POSTMARK_API_TOKEN') as string,
'login-link',
);

const handler = new TokenAuthHandler('/admin/_github', encoder, backend, {
tokenLifetime: 300,
});
return handler.handle(request, context.next);
};
9 changes: 9 additions & 0 deletions apps/website/netlify/functions/github-proxy.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { Context } from '@netlify/functions';
import { githubProxy } from '@amazeelabs/decap-cms-backend-token-auth/proxy';

export default function (request: Request, context: Context) {
if (!process.env.DECAP_GITHUB_TOKEN) {
throw new Error('Missing environment variable DECAP_GITHUB_TOKEN.');
}
return githubProxy(request, process.env.DECAP_GITHUB_TOKEN, '/admin/_github');
}
8 changes: 7 additions & 1 deletion apps/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"private": true,
"dependencies": {
"@amazeelabs/bridge-gatsby": "^1.2.7",
"@amazeelabs/decap-cms-backend-token-auth": "workspace:*",
"@amazeelabs/token-auth-middleware": "workspace:*",
"@amazeelabs/cloudinary-responsive-image": "^1.6.15",
"@amazeelabs/gatsby-plugin-operations": "^1.1.3",
"@amazeelabs/gatsby-plugin-static-dirs": "^1.0.1",
Expand All @@ -24,11 +26,13 @@
"gatsby-source-filesystem": "^5.13.0",
"image-size": "^1.1.1",
"mime-types": "^2.1.35",
"netlify-cli": "^17.11.0",
"netlify-cli": "^17.17.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@netlify/functions": "^2.6.0",
"@netlify/edge-functions": "^2.3.1",
"@testing-library/react": "^14.1.2",
"@types/react": "^18.2.46",
"@types/react-dom": "^18.2.18",
Expand All @@ -41,7 +45,9 @@
"test:static": "tsc --noEmit && eslint '**/*.{ts,tsx,js,jsx}' --ignore-path='./.gitignore'",
"build:gatsby": "pnpm build:dotenv && gatsby build",
"build:dotenv": "rm -rf .env && echo \"DRUPAL_EXTERNAL_URL='$DRUPAL_EXTERNAL_URL'\nDRUPAL_INTERNAL_URL='$DRUPAL_INTERNAL_URL'\" >> .env",
"full-rebuild": "pnpm clean && pnpm turbo:rebuild",
"rebuild": "gatsby build",
"turbo:rebuild": "turbo rebuild",
"start:cms": "pnpm run --filter @custom/cms start",
"build": "CLOUDINARY_CLOUDNAME=test start-test start:cms 8888 build:gatsby",
"start": "publisher",
Expand Down
11 changes: 11 additions & 0 deletions apps/website/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@
"styles.css"
],
"outputs": [".cache/**", ".netlify/**", "public/**", ".env"]
},
"rebuild": {
"dependsOn": ["prep"],
"inputs": [
"src/**",
"gatsby-node.js",
"gatsby-config.js",
"gatsby-browser.ts",
"gatsby-ssr.ts"
],
"outputs": ["public/**"]
}
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"commit": "git-cz",
"test:format": "pnpm test:format:root --check && pnpm test:format:workspaces --check",
"test:format:fix": "pnpm test:format:root --write && pnpm test:format:workspaces --write",
"test:format:root": "pnpm prettier '**/*.{js,cjs,mjs,ts,jsx,tsx,gql,graphql,graphqls,md,mdx,json}' --ignore-path='./.prettierignore'",
"test:format:workspaces": "pnpm --workspace-concurrency=1 -r exec prettier '**/*.{js,cjs,mjs,ts,jsx,tsx,gql,graphql,graphqls,md,mdx,json}' --ignore-path='./.gitignore'",
"test:format:root": "pnpm prettier '**/*.{js,cjs,mjs,ts,jsx,tsx,gql,graphql,graphqls,md,mdx,json,htm,html}' --ignore-path='./.prettierignore'",
"test:format:workspaces": "pnpm --workspace-concurrency=1 -r exec prettier '**/*.{js,cjs,mjs,ts,jsx,tsx,gql,graphql,graphqls,md,mdx,json,htm,html}' --ignore-path='./.gitignore'",
"turbo:local": "if [ -z $CI ]; then echo $(date)$RANDOM > apps/cms/turbo-seed.txt; fi",
"turbo:test": "pnpm turbo:local && turbo test:unit --no-daemon --go-fallback --output-logs=new-only && turbo test:integration --no-daemon --go-fallback --output-logs=new-only --concurrency=1",
"turbo:test:quick": "pnpm turbo:local && turbo test:unit --no-daemon --go-fallback --output-logs=new-only",
Expand Down
4 changes: 4 additions & 0 deletions packages/decap-cms-backend-token-auth/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
extends: ['@amazeelabs/eslint-config'],
root: true,
};
1 change: 1 addition & 0 deletions packages/decap-cms-backend-token-auth/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build
4 changes: 4 additions & 0 deletions packages/decap-cms-backend-token-auth/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
**
!build/*
!CHANGELOG.md
!README.md
1 change: 1 addition & 0 deletions packages/decap-cms-backend-token-auth/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"@amazeelabs/prettier-config"
48 changes: 48 additions & 0 deletions packages/decap-cms-backend-token-auth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Decap Token-Auth backend

Decap backend that uses token authentication instead of Netlify Identity or
similar services. This package is meant to be used in combination with the
`@amazeelabs/token-auth-middleware` package. It contains a proxy service that
can run as a serverless function and handle Decap requests with a dedicated
Github token.

## Usage

For example, create a netlify edge function and simply pass the request to a
proxy.

```typescript
import type { Context } from '@netlify/functions';
import { githubProxy } from '@amazeelabs/decap-cms-backend-token-auth/proxy';

export default function (request: Request, context: Context) {
if (!process.env.DECAP_GITHUB_TOKEN) {
throw new Error('No Github token configured');
}
return githubProxy(request, process.env.DECAP_GITHUB_TOKEN, '/admin/_github');
}
```

> [!IMPORTANT]
> Make sure to configure `@amazeelabs/token-auth-middleware` to use the same
> `/admin/_github` path and protect it properly.
Then inject and configure the `TokenAuthBackend` in Decap CMS.

```typescript
import { TokenAuthBackend } from '@amazeelabs/decap-cms-backend-token-auth';
import CMS from 'decap-cms-app';

CMS.registerBackend('token-auth', TokenAuthBackend);

CMS.init({
config: {
backend: {
name: 'token-auth',
api_root: '/admin/_github',
repo: 'myorg/myrepo',
branch: 'main',
},
},
});
```
54 changes: 54 additions & 0 deletions packages/decap-cms-backend-token-auth/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "@amazeelabs/decap-cms-backend-token-auth",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"exports": {
"./proxy": {
"import": "./build/proxy.js"
},
"./backend": {
"import": "./build/backend.js"
}
},
"typesVersions": {
"*": {
"proxy": [
"build/proxy.d.ts"
],
"backend": [
"build/backend.d.ts"
]
}
},
"scripts": {
"test:static": "tsc --noEmit && eslint \"**/*.{ts,tsx,js,jsx}\" --ignore-path=\"./.gitignore\"",
"test:unit": "vitest run --passWithNoTests",
"prep": "rm -rf build && tsc -p tsconfig.build.json",
"watch": "tsc --watch -p tsconfig.build.json"
},
"dependencies": {
"@amazeelabs/token-auth-middleware": "workspace:*",
"@emotion/styled": "^11.11.0",
"decap-cms-backend-github": "^3.1.0",
"decap-cms-lib-util": "^3.0.2",
"decap-cms-ui-default": "^3.1.0"
},
"peerDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/semaphore": "^1.1.4",
"@octokit/types": "^12.6.0",
"@amazeelabs/eslint-config": "1.4.43",
"@amazeelabs/prettier-config": "1.1.3",
"@types/node": "18.19.17",
"@types/react": "^18.2.60",
"vitest": "^1.3.1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Loading

0 comments on commit 2aefbe9

Please sign in to comment.