Skip to content

Commit

Permalink
make the parent domain parameterized/dynamic
Browse files Browse the repository at this point in the history
  • Loading branch information
mhuebert committed May 25, 2024
1 parent de925fd commit ef45487
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 21 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/publish_website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ jobs:
contents: 'read'
id-token: 'write'

env:
WEBSITE_DIR: './public'

steps:
- uses: 'actions/checkout@v4'

Expand All @@ -32,4 +29,8 @@ jobs:

- name: Deploy to Google Cloud Storage
run: |
gcloud storage rsync --recursive --delete-unmatched-destination-objects --cache-control 'public, max-age=60' $WEBSITE_DIR gs://gen-website-private/${{github.repository}}
WEBSITE_DIR='./public'
PARENT_DOMAIN='gen.dev'
SUBDOMAIN=${{github.event.repository.name}}
BUCKET_PATH="gs://gen-website-private/$PARENT_DOMAIN/$SUBDOMAIN"
gcloud storage rsync --recursive --delete-unmatched-destination-objects --cache-control 'public, max-age=60' $WEBSITE_DIR $BUCKET_PATH
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ There is also a second identity pool, `gen-website-private-publishers`, which gr
within GitHub Actions.

- Using this identity pool, a GitHub action in any probcomp website can modify the `gen-website-private` bucket without restriction.
- To enable App Engine to create signed blobs (time-limited links to files in the private bucket), I added the required permission via the following command (using the console UI didn't work):
- To enable App Engine to create signed blobs (time-limited links to files in the private bucket), I added the required permission via the following command (using the console UI didn't work, [this](https://stackoverflow.com/a/76493825) helped):
```
gcloud projects add-iam-policy-binding probcomp-caliban --member=serviceAccount:probcomp-caliban@appspot.gserviceaccount.com --role='roles/iam.serviceAccountTokenCreator'
```

### SSL
### SSL / Custom Domains

To publish to `www.gen.dev`, set `SUBDOMAIN` to `www`. To publish to a `PARENT_DOMAIN` other than `gen.dev`, an additional custom domain must be added via App Engine in Google Cloud.

[These instructions](https://gist.github.com/patmigliaccio/d559035e1aa7808705f689b20d7b3fd3) were essential to enabling SSL for a wildcard
subdomain on App Engine. I created an origin certificate in Cloudflare, appended the [Cloudflare Origin CA root certificate (ECC PEM)](https://developers.cloudflare.com/ssl/origin-configuration/origin-ca#cloudflare-origin-ca-root-certificate) to the PEM file, and converted the private key to RSA using the following command (note the `-traditional` flag):
Expand Down
29 changes: 14 additions & 15 deletions server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
// - Paths without an extension are served `index.html` to support Single Page Applications (SPAs).
// - Paths ending with a slash are served the `index.html` of the directory.

// URLs are expected to be in the form `REPO.gen.dev/foo` for production or,
// for development/testing, `localhost:3000/REPO/foo`.
// URLs are expected to be in the form `subdomain.gen.dev/foo` for production or,
// for development/testing, `localhost:3000/subdomain/foo`.

import { Storage } from '@google-cloud/storage';
import express from 'express';
Expand All @@ -15,8 +15,6 @@ import path from 'path';
import { getMimeType } from 'stream-mime-type';

const { PORT, BUCKET_NAME } = process.env;
const HOST_REPO_REGEX = /^(.+)\.gen\.dev$/;
const BUCKET_PREFIX = 'probcomp'

const HTML_MAX_AGE = 60;

Expand Down Expand Up @@ -65,19 +63,19 @@ const redirectFile = async (res, path) => {
return res.redirect(301, signedUrl);
};

const handleFileRequest = async (repo, filePath, res) => {
const handleFileRequest = async (parentDomain, subDomain, filePath, res) => {
// Handles file requests by determining the appropriate file path and serving the file.

if (filePath.endsWith('/')) {
// If the path ends with '/', serve the directory index.html
filePath = path.join(filePath, 'index.html');
} else if (!getExtension(filePath)) {
// If there is no extension, serve the main repo index.html
// If there is no extension, serve the subdomain's index.html
filePath = 'index.html';
}

// Construct the full path in the bucket
const bucketPath = path.join(BUCKET_PREFIX, repo, filePath);
const bucketPath = path.join(parentDomain, subDomain, filePath);
try {
// Serve HTML files directly, otherwise redirect to a signed URL
if (filePath.endsWith('.html')) {
Expand All @@ -98,22 +96,23 @@ const handleFileRequest = async (repo, filePath, res) => {
};

if (process.env.ENV == 'dev') {
app.get('/:repo/*', async (req, res) => {
await handleFileRequest(req.params.repo, req.params[0], res);
app.get('/:subDomain/*', async (req, res) => {
await handleFileRequest('gen.dev', req.params.subDomain, req.params[0], res);
});

app.get('/:repo', async (req, res) => {
await handleFileRequest(req.params.repo, '', res);
app.get('/:subDomain', async (req, res) => {
await handleFileRequest('gen.dev', req.params.subDomain, '', res);
});
}

app.get('/*', async (req, res) => {
const host = req.hostname;
const match = host.match(HOST_REPO_REGEX);
if (match) {
const repo = match[1];
const hostParts = host.split('.');
if (hostParts.length >= 3) {
const subDomain = hostParts[0];
const parentDomain = hostParts.slice(1).join('.');
const filePath = req.params[0];
await handleFileRequest(repo, filePath, res);
await handleFileRequest(parentDomain, subDomain, filePath, res);
} else {
res.status(404).send('Not Found');
}
Expand Down

0 comments on commit ef45487

Please sign in to comment.