Skip to content

Commit

Permalink
feat(endpoint-syndicate): support multiple methods of supplying a token
Browse files Browse the repository at this point in the history
  • Loading branch information
paulrobertlloyd committed Jan 7, 2023
1 parent 7128915 commit 364ac14
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 42 deletions.
38 changes: 38 additions & 0 deletions package-lock.json

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

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<form action="{{ application._syndicationEndpointPath }}" method="post">
{{ input({
name: "token",
name: "access_token",
type: "hidden",
value: token
}) | indent(2) }}
Expand Down
2 changes: 1 addition & 1 deletion packages/endpoint-syndicate/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default class SyndicateEndpoint {
this.mountPath = this.options.mountPath;
}

get routes() {
get routesPublic() {
router.post("/", syndicateController.post);

return router;
Expand Down
6 changes: 4 additions & 2 deletions packages/endpoint-syndicate/lib/controllers/syndicate.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { IndiekitError } from "@indiekit/error";
import { fetch } from "undici";
import { findBearerToken } from "../token.js";
import { getPostData } from "../utils.js";

export const syndicateController = {
async post(request, response, next) {
try {
const { application, publication } = request.app.locals;
const token = request.query.token || request.body.token;
const bearerToken = findBearerToken(request);

const sourceUrl =
request.query.source_url || request.body.syndication?.source_url;
const redirectUri =
Expand Down Expand Up @@ -76,7 +78,7 @@ export const syndicateController = {
method: "POST",
headers: {
accept: "application/json",
authorization: `Bearer ${token}`,
authorization: `Bearer ${bearerToken}`,
"content-type": "application/json",
},
body: JSON.stringify({
Expand Down
57 changes: 57 additions & 0 deletions packages/endpoint-syndicate/lib/token.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import process from "node:process";
import { IndiekitError } from "@indiekit/error";
import jwt from "jsonwebtoken";

export const findBearerToken = (request) => {
if (request.headers?.["x-webhook-signature"]) {
const signature = request.headers["x-webhook-signature"];
const verifiedToken = verifyToken(signature);
const bearerToken = signToken(verifiedToken, request.body.url);
return bearerToken;
}

if (request.body?.access_token) {
const bearerToken = request.body.access_token;
delete request.body.access_token;
return bearerToken;
}

if (request.query?.token) {
const bearerToken = request.query.token;
return bearerToken;
}

throw IndiekitError.invalidRequest("No bearer token provided by request");
};

/**
* Generate short-lived bearer token with update scope
*
* @param {object} verifiedToken - JSON Web Token
* @param {string} url - Publication URL
* @returns {string} Signed JSON Web Token
*/
export const signToken = (verifiedToken, url) =>
jwt.sign(
{
me: url,
scope: "update",
},
process.env.SECRET,
{
expiresIn: "10m",
}
);

/**
* Verify that token provided by signature was issued by Netlify
*
* @param {string} signature - JSON Web Signature
* @returns {object} JSON Web Token
* @see {@link https://docs.netlify.com/site-deploys/notifications/#payload-signature}
*/
export const verifyToken = (signature) =>
jwt.verify(signature, process.env.WEBHOOK_SECRET, {
algorithms: ["HS256"],
issuer: ["netlify"],
});
1 change: 1 addition & 0 deletions packages/endpoint-syndicate/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"dependencies": {
"@indiekit/error": "^1.0.0-beta.1",
"express": "^4.17.1",
"jsonwebtoken": "^9.0.0",
"undici": "^5.2.0"
},
"publishConfig": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ test("Returns no post record for URL", async (t) => {
const request = supertest.agent(server);
const result = await request
.post("/syndicate")
.auth(testToken(), { type: "bearer" })
.query({ token: testToken() })
.set("accept", "application/json")
.query({ source_url: "https://website.example/notes/foobar/" });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ test("Returns no post records", async (t) => {
const request = supertest.agent(server);
const result = await request
.post("/syndicate")
.auth(testToken(), { type: "bearer" })
.query({ token: testToken() })
.set("accept", "application/json");

t.is(result.status, 200);
Expand Down
Loading

0 comments on commit 364ac14

Please sign in to comment.