From 86f06bc1e8ed9539e4d6efdd10159ba62956f9c5 Mon Sep 17 00:00:00 2001 From: Chen Hui Jing <1461498+huijing@users.noreply.github.com> Date: Mon, 16 Dec 2024 19:31:57 +0800 Subject: [PATCH] Upgrade to Astro 5 and convert to new Content Layer API --- astro.config.mjs | 17 +++--- package.json | 11 ++-- src/components/blog/CommunityLinks.astro | 17 ++++++ src/components/{pages => blog}/LargeImg.astro | 0 src/components/blog/Pagination.astro | 60 +++++++++++++++++++ src/content.config.ts | 24 ++++++++ ...graveyard-of-possible-protocol-features.md | 7 ++- ...nect-all-blockchains-and-value-networks.md | 7 ++- ...ughts-on-scaling-interledger-connectors.md | 7 ++- .../blog/2024-04-10-the-telemetry-tale.md | 9 +-- .../2024-07-09-simple-open-payments-guide.md | 7 ++- ...4-07-30-open-payments-cinderella-story.mdx | 9 +-- .../blog/2024-08-13-interledger-universe.mdx | 7 ++- .../blog/2024-09-06-integration-tests.mdx | 14 ++--- .../2024-09-23-rafiki-code-architecture.mdx | 47 +++++++++------ .../2024-10-11-where-did-rafiki-money-go.mdx | 15 ++--- ...024-10-25-rafikis-first-security-audit.mdx | 35 +++++++---- ...12-03-e2e-testing-wm-browser-extension.mdx | 21 ++----- .../blog/2024-12-11-rafiki-beta-release.mdx | 38 ++++++------ src/content/config.ts | 19 ------ src/layouts/BlogLayout.astro | 4 ++ src/pages/blog/[...id].astro | 21 +++++++ src/pages/blog/[...page].astro | 14 ++++- src/pages/blog/[...slug].astro | 14 ----- 24 files changed, 272 insertions(+), 152 deletions(-) create mode 100644 src/components/blog/CommunityLinks.astro rename src/components/{pages => blog}/LargeImg.astro (100%) create mode 100644 src/components/blog/Pagination.astro create mode 100644 src/content.config.ts delete mode 100644 src/content/config.ts create mode 100644 src/pages/blog/[...id].astro delete mode 100644 src/pages/blog/[...slug].astro diff --git a/astro.config.mjs b/astro.config.mjs index 5230497..24bdd53 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -2,6 +2,8 @@ import { defineConfig } from "astro/config"; import starlight from "@astrojs/starlight"; import starlightLinksValidator from "starlight-links-validator"; +import mdx from "@astrojs/mdx"; + // https://astro.build/config export default defineConfig({ site: "https://interledger.org", @@ -37,18 +39,18 @@ export default defineConfig({ }, }, { - tag: 'script', + tag: "script", attrs: { defer: true, - 'data-website-id': '50d81dd1-bd02-4f82-8a55-34a09ccbbbd9', - src: 'https://ilf-site-analytics.netlify.app/script.js', - 'data-domains': 'interledger.org' - } - } + "data-website-id": "50d81dd1-bd02-4f82-8a55-34a09ccbbbd9", + src: "https://ilf-site-analytics.netlify.app/script.js", + "data-domains": "interledger.org", + }, + }, ], components: { Header: "./src/components/Header.astro", - PageSidebar: './src/components/PageSidebar.astro' + PageSidebar: "./src/components/PageSidebar.astro", }, social: { github: "https://github.com/interledger", @@ -132,6 +134,7 @@ export default defineConfig({ }, }, }), + mdx(), ], server: { port: 1103, diff --git a/package.json b/package.json index 9c944c4..9060d4d 100644 --- a/package.json +++ b/package.json @@ -9,16 +9,17 @@ "astro": "astro" }, "dependencies": { - "@astrojs/node": "^8.3.4", - "@astrojs/starlight": "^0.29.0", - "@interledger/docs-design-system": "^0.5.2", + "@astrojs/mdx": "^4.0.2", + "@astrojs/node": "^9.0.0", + "@astrojs/starlight": "^0.30.1", + "@interledger/docs-design-system": "^0.5.5", "@types/showdown": "^2.0.6", - "astro": "^4.16.11", + "astro": "^5.0.5", "html-to-text": "^9.0.5", "markdown-it": "^14.1.0", "node-html-parser": "^6.1.13", "sharp": "^0.33.5", "showdown": "^2.1.0", - "starlight-links-validator": "^0.13.2" + "starlight-links-validator": "^0.13.4" } } diff --git a/src/components/blog/CommunityLinks.astro b/src/components/blog/CommunityLinks.astro new file mode 100644 index 0000000..17d3f78 --- /dev/null +++ b/src/components/blog/CommunityLinks.astro @@ -0,0 +1,17 @@ +--- +--- +
+ +

As we are open source, you can easily check our work on GitHub. If the work mentioned here inspired you, we welcome your contributions. You can join our community slack or participate in the next community call, which takes place each second Wednesday of the month.

+ +

If you want to stay updated with all open opportunities and news from the Interledger Foundation, you can subscribe to our newsletter.

+ + diff --git a/src/components/pages/LargeImg.astro b/src/components/blog/LargeImg.astro similarity index 100% rename from src/components/pages/LargeImg.astro rename to src/components/blog/LargeImg.astro diff --git a/src/components/blog/Pagination.astro b/src/components/blog/Pagination.astro new file mode 100644 index 0000000..cd0fd26 --- /dev/null +++ b/src/components/blog/Pagination.astro @@ -0,0 +1,60 @@ +--- +const { length, currentPage, firstUrl, prevUrl, nextUrl, lastUrl } = Astro.props; + +const paginationList = Array.from({length}, (_, i) => i + 1); +--- + + + diff --git a/src/content.config.ts b/src/content.config.ts new file mode 100644 index 0000000..7c28984 --- /dev/null +++ b/src/content.config.ts @@ -0,0 +1,24 @@ +import { z, defineCollection } from "astro:content"; +import { glob } from "astro/loaders"; +import { docsLoader, i18nLoader } from "@astrojs/starlight/loaders"; +import { docsSchema, i18nSchema } from "@astrojs/starlight/schema"; + +const blogCollection = defineCollection({ + loader: glob({ pattern: "**/[^_]*.{md,mdx}", base: "./src/content/blog" }), + schema: z.object({ + title: z.string(), + description: z.string(), + slug: z.string(), + date: z.date(), + image: z.string().optional(), + tags: z.array(z.string()), + authors: z.array(z.string()), + author_urls: z.array(z.string()), + }), +}); + +export const collections = { + docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), + i18n: defineCollection({ loader: i18nLoader(), schema: i18nSchema() }), + blog: blogCollection, +}; diff --git a/src/content/blog/2018-01-29-simplifying-interledger-the-graveyard-of-possible-protocol-features.md b/src/content/blog/2018-01-29-simplifying-interledger-the-graveyard-of-possible-protocol-features.md index 6298792..8c630cf 100644 --- a/src/content/blog/2018-01-29-simplifying-interledger-the-graveyard-of-possible-protocol-features.md +++ b/src/content/blog/2018-01-29-simplifying-interledger-the-graveyard-of-possible-protocol-features.md @@ -1,11 +1,12 @@ --- -layout: ../../layouts/BlogLayout.astro title: "Simplifying Interledger: The Graveyard of Possible Protocol Features" description: As the development of the Interledger Protocol (ILP) nears completion, I thought we should take a moment to remember some of the many core protocol features we’ve killed off along the way. date: 2018-01-29 slug: simplifying-interledger-the-graveyard-of-possible-protocol-features -authors: [Evan Schwartz] -author_urls: [https://www.linkedin.com/in/evanmarkschwartz/] +authors: + - Evan Schwartz +author_urls: + - https://www.linkedin.com/in/evanmarkschwartz/ external_url: https://medium.com/interledger-blog/simplifying-interledger-the-graveyard-of-possible-protocol-features-b35bf67439be tags: - Interledger diff --git a/src/content/blog/2018-10-03-interledger-how-to-interconnect-all-blockchains-and-value-networks.md b/src/content/blog/2018-10-03-interledger-how-to-interconnect-all-blockchains-and-value-networks.md index 7aa11d5..3ebb272 100644 --- a/src/content/blog/2018-10-03-interledger-how-to-interconnect-all-blockchains-and-value-networks.md +++ b/src/content/blog/2018-10-03-interledger-how-to-interconnect-all-blockchains-and-value-networks.md @@ -1,11 +1,12 @@ --- -layout: ../../layouts/BlogLayout.astro title: "Interledger: How to Interconnect All Blockchains and Value Networks" description: "Interledger was born out of a project to build a blockchain-agnostic smart contracts platform. A key challenge was neutrality: how could a decentralized app buy resources like storage and computing, without being tied to a specific blockchain?" date: 2018-10-03 slug: interledger-how-to-interconnect-all-blockchains-and-value-networks -authors: [Evan Schwartz] -author_urls: [https://www.linkedin.com/in/evanmarkschwartz/] +authors: + - Evan Schwartz +author_urls: + - https://www.linkedin.com/in/evanmarkschwartz/ external_url: https://medium.com/xpring/interledger-how-to-interconnect-all-blockchains-and-value-networks-74f432e64543 tags: - Interledger diff --git a/src/content/blog/2019-01-23-thoughts-on-scaling-interledger-connectors.md b/src/content/blog/2019-01-23-thoughts-on-scaling-interledger-connectors.md index 81a99df..869db5d 100644 --- a/src/content/blog/2019-01-23-thoughts-on-scaling-interledger-connectors.md +++ b/src/content/blog/2019-01-23-thoughts-on-scaling-interledger-connectors.md @@ -1,11 +1,12 @@ --- -layout: ../../layouts/BlogLayout.astro title: Thoughts on Scaling Interledger Connectors description: Streaming payments mean that Interledger connectors need to process huge volumes of Interledger packets, but the current reference implementation is hard to run at scale. date: 2019-01-23 slug: thoughts-on-scaling-interledger-connectors -authors: [Evan Schwartz] -author_urls: [https://www.linkedin.com/in/evanmarkschwartz/] +authors: + - Evan Schwartz +author_urls: + - https://www.linkedin.com/in/evanmarkschwartz/ external_url: https://medium.com/interledger-blog/thoughts-on-scaling-interledger-connectors-7e3cad0dab7f tags: - Interledger diff --git a/src/content/blog/2024-04-10-the-telemetry-tale.md b/src/content/blog/2024-04-10-the-telemetry-tale.md index 3256377..b554f38 100644 --- a/src/content/blog/2024-04-10-the-telemetry-tale.md +++ b/src/content/blog/2024-04-10-the-telemetry-tale.md @@ -1,11 +1,12 @@ --- -layout: ../../layouts/BlogLayout.astro title: "The Telemetry Tale: A Journey into the Metrics of Interledger" description: When simple metrics are paired with complex cloud solutions and important privacy considerations, the implementation process becomes significantly more complicated. date: 2024-04-10 slug: the-telemetry-tale -authors: [Sarah Jones] -author_urls: [https://www.linkedin.com/in/sarah-jones-ba6bb6b9] +authors: + - Sarah Jones +author_urls: + - https://www.linkedin.com/in/sarah-jones-ba6bb6b9 tags: - Interledger - Telemetry @@ -146,6 +147,6 @@ A lot of what we’ve covered in this article could be construed as scope creep. That said, we could have benefited from more time upfront for understanding and planning instead of simply diving straight in. Perhaps, our work week eagerness may have led us to jump in too quickly. It is with a great sense of accomplishment that we now have telemetry running in our development environment where we are seeing how it holds up against our test data and hope it will be used in a production environment shortly. -We look forward to having a real handle on the pulse of the ILP network soon. Of course, this journey is far from its conclusion. Telemetry, by its nature, is an ever-evolving domain, requiring adaptation to meet the network's growing needs and challenges. Having laid a solid foundation, future developments should be smoother. +We look forward to having a real handle on the pulse of the ILP network soon. Of course, this journey is far from its conclusion. Telemetry, by its nature, is an ever-evolving domain, requiring adaptation to meet the network's growing needs and challenges. Having laid a solid foundation, future developments should be smoother. As we reflect on our path thus far, the question is: "Given our current knowledge and experiences, would we approach this project differently?" In hindsight, we would have used self-hosted Prometheus and Grafana instances from the start and avoided many of the problems we faced. This is a goal which remains on our roadmap, in order to provide us with the flexibility we seek. Some of the back and forth on our decision-making would have been smoother had we spent some more time in discussions at the start about what privacy factors to keep in mind and how public our results were intended to be. diff --git a/src/content/blog/2024-07-09-simple-open-payments-guide.md b/src/content/blog/2024-07-09-simple-open-payments-guide.md index cc87033..4a4595c 100644 --- a/src/content/blog/2024-07-09-simple-open-payments-guide.md +++ b/src/content/blog/2024-07-09-simple-open-payments-guide.md @@ -1,11 +1,12 @@ --- -layout: ../../layouts/BlogLayout.astro title: "A Simple Guide to the Open Payments Standard" description: Learn how the Open Payments standard makes online payments easier and more accessible for everyone. date: 2024-07-09 slug: simple-open-payments-guide -authors: [Sarah Jones] -author_urls: [https://www.linkedin.com/in/sarah-jones-ba6bb6b9] +authors: + - Sarah Jones +author_urls: + - https://www.linkedin.com/in/sarah-jones-ba6bb6b9 tags: - Interledger - Open Payments diff --git a/src/content/blog/2024-07-30-open-payments-cinderella-story.mdx b/src/content/blog/2024-07-30-open-payments-cinderella-story.mdx index 8495178..39654ae 100644 --- a/src/content/blog/2024-07-30-open-payments-cinderella-story.mdx +++ b/src/content/blog/2024-07-30-open-payments-cinderella-story.mdx @@ -1,18 +1,19 @@ --- -layout: ../../layouts/BlogLayout.astro title: "Open Payments: The Cinderella Story of Finding a Fitting Authorization Method" description: A breakdown of the unique needs that an authorization method for Open Payments needs to be able to fulfill. date: 2024-07-30 slug: open-payments-cinderella-story -authors: [Nathan Lie] -author_urls: [https://www.linkedin.com/in/nathan-lie-138a73121] +authors: + - Nathan Lie +author_urls: + - https://www.linkedin.com/in/nathan-lie-138a73121 tags: - Interledger - Open Payments - GNAP --- -import LargeImg from "/src/components/pages/LargeImg.astro"; +import LargeImg from "/src/components/blog/LargeImg.astro"; ## The Internet Runs on OAuth 2.0 diff --git a/src/content/blog/2024-08-13-interledger-universe.mdx b/src/content/blog/2024-08-13-interledger-universe.mdx index ac3bdbc..6429804 100644 --- a/src/content/blog/2024-08-13-interledger-universe.mdx +++ b/src/content/blog/2024-08-13-interledger-universe.mdx @@ -1,12 +1,13 @@ --- -layout: ../../layouts/BlogLayout.astro title: "The Interledger Universe" description: "Or: “What the heck are all those products and protocols?”" ogImageUrl: /developers/img/blog/2024-08-13/og-image.png date: 2024-08-13 slug: interledger-universe -authors: [Sabine Schaller] -author_urls: [https://www.linkedin.com/in/sabineschaller] +authors: + - Sabine Schaller +author_urls: + - https://www.linkedin.com/in/sabineschaller tags: - Interledger - Interledger Protocol diff --git a/src/content/blog/2024-09-06-integration-tests.mdx b/src/content/blog/2024-09-06-integration-tests.mdx index d6c73f6..4bf60d4 100644 --- a/src/content/blog/2024-09-06-integration-tests.mdx +++ b/src/content/blog/2024-09-06-integration-tests.mdx @@ -1,18 +1,19 @@ --- -layout: ../../layouts/BlogLayout.astro title: "Leveling Up Rafiki Testing: Shifting from Manual to Automated" description: "How we automated our manual payment flow tests." date: 2024-09-06 slug: integration-tests -authors: [Blair Currey] -author_urls: [https://www.linkedin.com/in/blair-currey/] +authors: + - Blair Currey +author_urls: + - https://www.linkedin.com/in/blair-currey/ tags: - Rafiki - Open Payments - Testing --- -import LargeImg from "/src/components/pages/LargeImg.astro"; +import LargeImg from "/src/components/blog/LargeImg.astro"; [Rafiki](https://rafiki.dev/) is open source software that allows an [Account Servicing Entity](https://rafiki.dev/overview/overview#more-about-account-servicing-entities) to enable Interledger functionality on its users’ accounts, so testing is really important to us. Given the critical nature of handling payments, it's essential that our tests not only validate correctness but also build confidence for our integrators. @@ -118,10 +119,7 @@ Running tests from the host machine against services in Docker posed a problem w This sequence diagram illustrates how a request from the host machine resolves using the mapped hostnames. - + ## Conclusion diff --git a/src/content/blog/2024-09-23-rafiki-code-architecture.mdx b/src/content/blog/2024-09-23-rafiki-code-architecture.mdx index 4bb412e..43c9724 100644 --- a/src/content/blog/2024-09-23-rafiki-code-architecture.mdx +++ b/src/content/blog/2024-09-23-rafiki-code-architecture.mdx @@ -1,15 +1,17 @@ --- -layout: ../../layouts/BlogLayout.astro title: "Breaking Down Rafiki: What Makes Our Friend Tick" -description: 'A low-level introduction to the software packages that comprise Rafiki.' +description: "A low-level introduction to the software packages that comprise Rafiki." date: 2024-09-23 slug: rafiki-low-level-intro -authors: [Nathan Lie] -author_urls: [https://www.linkedin.com/in/nathan-lie-138a73121] +authors: + - Nathan Lie +author_urls: + - https://www.linkedin.com/in/nathan-lie-138a73121 tags: - Rafiki --- -import LargeImg from '/src/components/pages/LargeImg.astro' + +import LargeImg from "/src/components/blog/LargeImg.astro"; ## Introduction @@ -17,31 +19,35 @@ It has been said that the Interledger Foundation upholds open technology as one It has _not_ been said, however, how one comes to intimately understand Rafiki. It's not impossible, to be sure, but the Interledger endeavor has been around for long enough that a write-up at a lower level is warranted. -So, what makes Rafiki tick? What do we see when we venture beyond _what_ Rafiki does and into _how_ it does those things? +So, what makes Rafiki tick? What do we see when we venture beyond _what_ Rafiki does and into _how_ it does those things? ### Disclaimer + This article assumes the reader has high-level knowledge of the following concepts: -* [Open Payments](https://openpayments.dev/introduction/overview/) -* [Interledger](https://interledger.org/developers/get-started/#how-does-interledger-work) +- [Open Payments](https://openpayments.dev/introduction/overview/) +- [Interledger](https://interledger.org/developers/get-started/#how-does-interledger-work) This article also assumes that its readers already have high-level knowledge of [Rafiki](https://rafiki.dev/overview/overview/) itself, and that they understand on that level how it accomplishes being an Interledger node and an Open Payments server. ## Components - + Rafiki is comprised primarily of three packages: -* A [`backend`](https://github.com/interledger/rafiki/tree/main/packages/backend) package that extends an API for managing Open Payments resources like Incoming or Outgoing Payments, an Admin API, and an API from the Interledger connector to accept ILP packets. -* An [`auth`](https://github.com/interledger/rafiki/tree/main/packages/auth) package that provide third parties with a method of acquiring authorization to manage Open Payments resources on the Rafiki instance's associated `backend` package. It also extends an Admin API as well. -* A [`frontend`](https://github.com/interledger/rafiki/tree/main/packages/frontend) that serves as an Admin-level UI for that Rafiki instance. It allows the manager of that Rafiki instance to directly manage items such as other peers on the Interledger network or what currencies it supports. +- A [`backend`](https://github.com/interledger/rafiki/tree/main/packages/backend) package that extends an API for managing Open Payments resources like Incoming or Outgoing Payments, an Admin API, and an API from the Interledger connector to accept ILP packets. +- An [`auth`](https://github.com/interledger/rafiki/tree/main/packages/auth) package that provide third parties with a method of acquiring authorization to manage Open Payments resources on the Rafiki instance's associated `backend` package. It also extends an Admin API as well. +- A [`frontend`](https://github.com/interledger/rafiki/tree/main/packages/frontend) that serves as an Admin-level UI for that Rafiki instance. It allows the manager of that Rafiki instance to directly manage items such as other peers on the Interledger network or what currencies it supports. Rafiki also maintains a few other utility packages: -* A [`documentation`](https://github.com/interledger/rafiki/tree/main/packages/documentation) package that the documentation website (https://rafiki.dev/) is maintained from. -* A [`mock-account-service-lib`](https://github.com/interledger/rafiki/tree/main/packages/mock-account-service-lib) that provides a useful library to mock the utilities used by the mock Account Service Providers in the test local environment. -* A [`token-introspection`](https://github.com/interledger/rafiki/tree/main/packages/token-introspection) package that creates a client to easily manage a GNAP token with an Open Payments Authorization server. +- A [`documentation`](https://github.com/interledger/rafiki/tree/main/packages/documentation) package that the documentation website (https://rafiki.dev/) is maintained from. +- A [`mock-account-service-lib`](https://github.com/interledger/rafiki/tree/main/packages/mock-account-service-lib) that provides a useful library to mock the utilities used by the mock Account Service Providers in the test local environment. +- A [`token-introspection`](https://github.com/interledger/rafiki/tree/main/packages/token-introspection) package that creates a client to easily manage a GNAP token with an Open Payments Authorization server. All of these packages are managed together as a monorepo using [pnpm](https://pnpm.io/motivation). @@ -49,9 +55,9 @@ All of these packages are managed together as a monorepo using [pnpm](https://pn Both the `backend` and `auth` packages are largely built in the same way. They both leverage the same three Node.js frameworks: -* [KoaJS](https://koajs.com/) -* [AdonisJS](https://docs.adonisjs.com/guides/preface/introduction) -* [KnexJS](https://knexjs.org/guide/) +- [KoaJS](https://koajs.com/) +- [AdonisJS](https://docs.adonisjs.com/guides/preface/introduction) +- [KnexJS](https://knexjs.org/guide/) KoaJS is used as the framework for setting up the API routes, assigning functions to handle business logic for those routes, and wrapping those in middlewares for addtional functionality. It's a lot like an [Express server](https://expressjs.com/) if that helps with familiarity. @@ -136,6 +142,7 @@ In order fulfill the payments described in Open Payments resources and maintain The Authorization Server on Rafiki is structured similarly to the backend, in that it injects services into an IoC container which are retrieved by routes on Koa server to perform the business logic. [index.ts](https://github.com/interledger/rafiki/blob/main/packages/auth/src/index.ts) + ```ts wrap import { Ioc, IocContract } from '@adonisjs/fold' import { createGrantRoutes } from './grant/routes' @@ -162,6 +169,7 @@ container.singleton('grantRoutes', async (deps: IocContract) => { Again, note the route service for grants is mounted to the container, and then subsequently referenced when attaching service functions to the relevant routes. [app.ts](https://github.com/interledger/rafiki/blob/main/packages/auth/src/app.ts) + ```ts wrap const grantRoutes = await this.container.use('grantRoutes') @@ -194,6 +202,7 @@ Pages on the frontend acquire data to populate the view and send data in request ## Seeing Rafiki In Action If Docker is installed, the whole environment can be started locally with a single command: + ```ts wrap pnpm localenv:compose up ``` @@ -215,4 +224,4 @@ With any luck, this article should bridge the gap between loftier concepts like With even more luck, this article will be relevant for quite some time after publication, but if it isn't, it can serve as a recent entry in the [Interledger graveyard](https://interledger.org/developers/blog/simplifying-interledger-the-graveyard-of-possible-protocol-features). -For even more information, please peruse the [Rafiki documentation](https://rafiki.dev/overview/overview/). \ No newline at end of file +For even more information, please peruse the [Rafiki documentation](https://rafiki.dev/overview/overview/). diff --git a/src/content/blog/2024-10-11-where-did-rafiki-money-go.mdx b/src/content/blog/2024-10-11-where-did-rafiki-money-go.mdx index 9bc6d3d..768fd44 100644 --- a/src/content/blog/2024-10-11-where-did-rafiki-money-go.mdx +++ b/src/content/blog/2024-10-11-where-did-rafiki-money-go.mdx @@ -1,11 +1,12 @@ --- -layout: ../../layouts/BlogLayout.astro title: "Where did rafiki.money go?" description: "Or “The need for rebranding when something confuses people.”" date: 2024-10-11 slug: where-did-rafiki-money-go -authors: [Timea Nagy] -author_urls: [https://www.linkedin.com/in/nagy-timea-35483024] +authors: + - Timea Nagy +author_urls: + - https://www.linkedin.com/in/nagy-timea-35483024 tags: - Test Network --- @@ -44,13 +45,7 @@ Upon finalizing the visuals with our in-house illustrator, [Madalina Tantareanu] We were also able to account for designing the interactions, like hover states, which commonly get missed out if a static design file is used. - + ## Challenges we faced, interesting stuff we used diff --git a/src/content/blog/2024-10-25-rafikis-first-security-audit.mdx b/src/content/blog/2024-10-25-rafikis-first-security-audit.mdx index ca88eda..b51902c 100644 --- a/src/content/blog/2024-10-25-rafikis-first-security-audit.mdx +++ b/src/content/blog/2024-10-25-rafikis-first-security-audit.mdx @@ -1,40 +1,47 @@ --- -layout: ../../layouts/BlogLayout.astro title: "Rafiki's First Security Audit" description: "Takeaways from Rafiki's 2024 security audit." date: 2024-10-25 slug: rafikis-first-security-audit -authors: [Max Kurapov] -author_urls: [https://www.linkedin.com/in/mkurapov] +authors: + - Max Kurapov +author_urls: + - https://www.linkedin.com/in/mkurapov tags: - Rafiki - security - audit --- -At the beginning of the year, we were in contact with a security and penetration testing company to do an audit of Rafiki. Even though the software is still in its early stages, it is essential to gather feedback early to build a strong foundation for the software's security. The primary goals of the assessment were to evaluate several Rafiki components: the GraphQL Admin APIs, the frontend Admin UI component, as well as our underlying [ILPv4 protocol](https://interledger.org/developers/get-started/). The assessment was done using Rafiki’s local playground, based on the [Open Source Security Testing Methodology Manual (OSSTMM)](https://www.isecom.org/research.html) and [Open Source Web Application Security Project (OWASP)](https://owasp.org/) methodologies. +At the beginning of the year, we were in contact with a security and penetration testing company to do an audit of Rafiki. Even though the software is still in its early stages, it is essential to gather feedback early to build a strong foundation for the software's security. The primary goals of the assessment were to evaluate several Rafiki components: the GraphQL Admin APIs, the frontend Admin UI component, as well as our underlying [ILPv4 protocol](https://interledger.org/developers/get-started/). The assessment was done using Rafiki’s local playground, based on the [Open Source Security Testing Methodology Manual (OSSTMM)](https://www.isecom.org/research.html) and [Open Source Web Application Security Project (OWASP)](https://owasp.org/) methodologies. The audit presented eight vulnerabilities in total, with different risk levels: ![Results of the assessment](/developers/img/blog/2024-10-25/results.png) - Two items were not applicable to us: +Two items were not applicable to us: + - Lack of Transport Layer Protection: given this is our local playground environment, we run HTTP for ease of use. - Hardcoded Secret Credentials: automatic code review flagged hardcoded credentials, but this was only in our test files where we use mock data. The remaining six vulnerabilities were addressed as follows: ## Admin APIs + ### HMAC signing + While the assessment mentioned adding a security mechanism to our GraphQL Admin APIs in both the backend and auth packages as part of the report, this was a known priority even before the audit. Although these APIs should not be exposed to the wider internet in a Rafiki deployment, we want to provide our [Account Servicing Entities (ASEs)](https://rafiki.dev/overview/overview/#more-about-account-servicing-entities) running the software with as many security safeguards as possible. Given that the typical usage of the Admin APIs is through service-to-service requests, we chose to go with a simple and effective solution similar to what we had already integrated for our webhooks: adding HMAC signature support. This is done by having a shared key between the Rafiki services, and the integrator’s service. When calling the Admin API, the integrator generates a signature of the payload (containing a timestamp and request body) using HMAC with sha256 algorithm and the secret key. Upon receiving the request in the Admin API, backend and auth verifies this signature to validate the request’s authenticity & integrity. ### Disabling GraphQL Introspection Query + The assessment outlined a few recommendations against common GraphQL attacks, one of which was the disabling of the introspection query in production. Introspection can provide access into the whole structure of a GraphQL schema (types, queries, mutations, deprecated fields) which is useful during development, but can provide a lot of knowledge to bad actors looking to exploit the API. Based on the recommendation, we turned off introspection in production. ### Preventing Denial of Service GraphQL Attacks + Due to the structure of GraphQL APIs, it is sometimes not possible to avoid circular relationships between the models. As a result, bad actors can create requests containing circular queries, causing nested fields to be resolved recursively: + ```gql query { __schema { @@ -48,7 +55,7 @@ query { name type { name - ... + ... } } } @@ -57,6 +64,7 @@ query { } } ``` + Without proper handling, this can cause the server to grind to a halt trying to process these kinds of requests. The recommendation from the audit was to limit the depth of valid queries, such that no requests past a certain level of nesting can be resolved. In addition, there is a threat of field duplication attacks in GraphQL APIs: an attacker tries to overload the API by excessively requesting fields many times over in a single query. Even though standard GraphQL implementations end up correctly calling the underlying resolver (handler) only once per field, the GraphQL parser needs to do a lot of work to actually process the request, potentially leading to a denial of service (DoS). @@ -74,16 +82,20 @@ query GetAsset($id: String!) { } } ``` -This can be prevented by limiting queries that go above a certain complexity threshold, or by limiting the number of "tokens" (such as fields) allowed in a request. + +This can be prevented by limiting queries that go above a certain complexity threshold, or by limiting the number of "tokens" (such as fields) allowed in a request. We ended up [using](https://github.com/interledger/rafiki/pull/2537) a library called [`@escape.tech/graphql-armor`](https://escape.tech/graphql-armor/docs/getting-started/) to set different kinds of constraints to protect us from these kinds of attacks. ## Rafiki Admin UI (frontend package) + As part of the Rafiki software stack, we also publish a frontend package. This is a Remix application that enables managing a Rafiki instance using a web-interface. There are few common vulnerabilities that are common across web applications. One of them is clickjacking: a bad actor embeds a legitimate site in an iframe, and then uses several techniques to trick users into entering information meant for the original site in order to gather (or "highjack") clicks and keystrokes ultimately performing unintended actions on behalf of the user, such as submitting forms, making transactions, or altering account settings. In order to prevent this, the testers recommended adding an `X-Frame-Options` header in the responses from the web application. In the `X-Frame-Options` header, we now return the value of `SAMEORIGIN`, which allows framing only by pages with the same domain as in the response itself, preventing bad actors from framing the Rafiki Admin UI on malicious sites. ## Library vulnerabilities + Given we use a lot of different published libraries in Rafiki, we are vulnerable to security exploits found in them, and of course, their dependencies. During the assessment, the testers used the code scanning tool Snyk to find several vulnerable dependencies in the Rafiki repository. Even though we have renovate-bot to automatically open PRs to manage any outdated libraries, it wasn’t directly incorporated into our continuous integration (CI) pipeline. After the assessment, we added a few code scanners into our CI workflow: Trivy and Grype. Both of these tools have large databases of known exploits for libraries (similar to Snyk), and with each commit into a PR, Trivy and Gripe scan the build (and potentially, the to-be-published Docker image) for high-risk vulnerabilities and indicates it in the PR. This allows us to be more proactive in fixing these issues, instead of relying on less regular merges of dependency updates with renovate-bot. ## ILP & STREAM + Rafiki runs an ILP connector (using [STREAM](https://interledger.org/developers/rfcs/stream-protocol/) as the transport protocol) as part of its software. This is how two peered Rafiki instances interact and make payments between one another. One of the questions we wanted to ask the auditors during the assessment was, _"if you intercept an ILP packet, could you get any useful information out of it?"_. Using the local playground, we worked together with the auditors to capture ILP (STREAM) packets between the ILP connectors of two Rafiki instances. In the local playground, these requests are done over HTTP. Even though in a production environment the connector-to-connector communication would be done over HTTPS, it gave us visibility into what the requests & responses look like over an insecure protocol. The auditors observed that the ILP STREAM packets were properly encrypted in transit: @@ -91,8 +103,7 @@ One of the questions we wanted to ask the auditors during the assessment was, _" The STREAM transport protocol relies on exchanging a symmetric secret to encrypt messages out-of-band, i.e., without any cryptographic handshakes. In Rafiki, this is done through the use of Open Payments APIs, meaning that even if a bad actor were to inspect packets from the beginning of a STREAM connection, they wouldn't be able to gain any information to decrypt the messages. With this knowledge, combined with the actual observation of the STREAM packets, the auditors found that the encryption & secure data handling using the STREAM transport protocol was sound. This answered our question above: no, no useful information would be gained if one were to intercept these packets. -
-These were some of the findings we had as part of Rafiki's first security audit. -Going forward, we will be doing annual reviews of this nature within Rafiki, as well as the ecosystem as a whole. It is always helpful to get an experienced, outside perspective about how we can continue improving - particularly when it comes to vital aspects of building software, such as security. - - +
+These were some of the findings we had as part of Rafiki's first security audit. Going forward, we will be doing annual reviews +of this nature within Rafiki, as well as the ecosystem as a whole. It is always helpful to get an experienced, outside perspective +about how we can continue improving - particularly when it comes to vital aspects of building software, such as security. diff --git a/src/content/blog/2024-12-03-e2e-testing-wm-browser-extension.mdx b/src/content/blog/2024-12-03-e2e-testing-wm-browser-extension.mdx index 3fe1fe0..bd0e373 100644 --- a/src/content/blog/2024-12-03-e2e-testing-wm-browser-extension.mdx +++ b/src/content/blog/2024-12-03-e2e-testing-wm-browser-extension.mdx @@ -1,11 +1,12 @@ --- -layout: ../../layouts/BlogLayout.astro title: "End-to-end testing the Web Monetization browser extension" description: "E2E testing browser extensions? It's tricky, but we've got it covered." date: 2024-12-03 slug: e2e-testing-wm-browser-extension -authors: [Sid Vishnoi] -author_urls: [https://sidvishnoi.com?ref=ilf_engg_blog] +authors: + - Sid Vishnoi +author_urls: + - https://sidvishnoi.com?ref=ilf_engg_blog tags: - Web Monetization --- @@ -36,11 +37,7 @@ We can launch the browser with our extension loaded using the `--load-extension= function loadExtension(pathToExtension: string): Promise { const context = await chromium.launchPersistentContext("", { headless: true, - args: [ - `--headless=true`, - `--disable-extensions-except=${pathToExtension}`, - `--load-extension=${pathToExtension}`, - ], + args: [`--headless=true`, `--disable-extensions-except=${pathToExtension}`, `--load-extension=${pathToExtension}`], }); return context; } @@ -306,7 +303,7 @@ context.on("requestfinished", async function intercept(req) { if (!req.serviceWorker()) return; // we only care about service worker requests here if (isTheRequestWeAreAfter(req)) { - const json = await req.response().then(res => res.json()); + const json = await req.response().then((res) => res.json()); // ... use response body context.off("requestfinished", intercept); // we're responsible citizens @@ -376,9 +373,3 @@ Let's keep an eye on Playwright's development and hope for future updates that m We'll level up our testing game by diving deeper into browser-specific features like Edge's split view and adding more tests to cover every corner case. We'll push the extension to its limits, simulating different user interactions and trying to break it, to build a rock-solid extension that provides a great user experience. Want to dive deeper into our testing strategy? Check out our [GitHub repo for the Web Monetization extension](https://github.com/interledger/web-monetization-extension). We're always open to feedback and contributions, so feel free to submit a pull request! - ---- - -As we are open source, you can easily check our work on [GitHub](https://github.com/interledger/). If the work mentioned here inspired you, we welcome your contributions. You can join our [community slack](https://communityinviter.com/apps/interledger/interledger-working-groups-slack) or participate in the next [community call](https://docs.google.com/document/u/1/d/1T_Q_eRZtL8GluJR9rVADd7fvkB8mPluMk-d96LM4vlg/edit#heading=h.ybdhwl6k5886), which takes place each second Wednesday of the month. - -If you want to stay updated with all open opportunities and news from the Interledger Foundation, you can subscribe to our [newsletter](https://interledger.org/subscribe). diff --git a/src/content/blog/2024-12-11-rafiki-beta-release.mdx b/src/content/blog/2024-12-11-rafiki-beta-release.mdx index 95980a5..3dff438 100644 --- a/src/content/blog/2024-12-11-rafiki-beta-release.mdx +++ b/src/content/blog/2024-12-11-rafiki-beta-release.mdx @@ -1,11 +1,12 @@ --- -layout: ../../layouts/BlogLayout.astro title: "Rafiki Beta Release" -description: "The Wild is Calling" +description: "The Wild is Calling." date: 2024-12-11 slug: rafiki-beta-release -authors: [Tadej Golobic] -author_urls: [https://www.linkedin.com/in/tadej-golobic/] +authors: + - Tadej Golobic +author_urls: + - https://www.linkedin.com/in/tadej-golobic tags: - Interledger - Interledger Protocol @@ -32,25 +33,27 @@ Rafiki is a comprehensive software package that bundles up all Interledger funct Let us reflect on what this milestone includes - a powerful suite of capabilities that are set to redefine the world of open payments. -* **ILP connector:** The backbone of interconnectivity, housing the core functionality of the [Interledger Protocol](https://interledger.org/developers/get-started/). Like the internet transmits information in packets, the connector splits payments into small, self-contained payment packets with details such as amount, sender, and routing information. This approach enables seamless, secure and scalable financial transactions, ensuring compatibility across platforms, currencies and technologies while optimizing routing, distributing workloads, reducing bottlenecks, and enhancing reliability and scalability. -* **SPSP and Open Payments:** These application-layer protocols simplify and standardize payment flows, ensuring interoperability across diverse systems while reducing the complexity of integration. By facilitating clear communication between senders and receivers, they deliver a safe, reliable and user-friendly experience for online payments -* **Admin APIs:** Empowering you with the tools to take control. The Backend Admin API allows you to oversee critical operational aspects of your Rafiki instance, such as network relationships, assets, account configurations and liquidity. The Auth Admin API offers detailed oversight of grants, providing visibility into their status, associated accounts and permissions, while enabling key management actions, including revocation. -* **Rafiki Admin UI:** The Rafiki Admin application is a user-friendly interface designed to streamline the management of your Rafiki operations. It features a comprehensive dashboard for overseeing peers, assets, wallet addresses, liquidity, webhooks, and payments, serving as an intuitive front–end to Rafiki’s backend service. Additionally, Rafiki supports an optional integration with open-source identity & user management system [Ory Kratos](https://www.ory.sh/kratos/), allowing you to invite or remove users as needed. -![Rafiki Admin UI](/developers/img/blog/2024-12-11/rafiki-admin.png) -![Rafiki Admin UI - Payments](/developers/img/blog/2024-12-11/admin-ui-payments.png) -* **Security audit fixes:** Rafiki underwent its first comprehensive [security audit](https://interledger.org/developers/blog/rafikis-first-security-audit/), conducted by an external security firm to identify and address vulnerabilities. Key improvements include implementing HMAC signing for API requests, disabling GraphQL introspection in production, adding protections against denial-of-service (DoS) attacks, and preventing clickjacking in the Admin UI. Proactive dependency scanning was also integrated into the CI pipeline to mitigate library vulnerabilities. This external audit ensures a robust and secure foundation for Rafiki. Security is not a one-time effort; it is an ongoing commitment. As Rafiki evolves, we will continue conducting regular audits and proactively strengthening its defenses to maintain the highest standard of safety and trustworthiness. -* **Telemetry:** Gain real-time insights to understand and optimize your deployments. Rafiki’s telemetry captures key metrics, including the number of packets flowing through the system, the number of transactions, the total value sent through the network, as well as the average transaction value and time - all while preserving user privacy. [Check telemetry in action](https://rafikitelemetry.grafana.net/public-dashboards/f70c8a6033b14da5a9f1cb974def602a). -![Telemetry](/developers/img/blog/2024-12-11/telemetry.png) -* **New documentation:** Clear, concise, and crafted with precision, Rafiki’s [new documentation](https://rafiki.dev) is designed to empower integrators, developers and administrators alike. We understand that great tools need great instructions and our updated documentation reflects this philosophy. By making our documentation more accessible, detailed and actionable, we are ensuring that Rafiki is not only powerful but also easy to adopt and extend +- **ILP connector:** The backbone of interconnectivity, housing the core functionality of the [Interledger Protocol](https://interledger.org/developers/get-started/). Like the internet transmits information in packets, the connector splits payments into small, self-contained payment packets with details such as amount, sender, and routing information. This approach enables seamless, secure and scalable financial transactions, ensuring compatibility across platforms, currencies and technologies while optimizing routing, distributing workloads, reducing bottlenecks, and enhancing reliability and scalability. +- **SPSP and Open Payments:** These application-layer protocols simplify and standardize payment flows, ensuring interoperability across diverse systems while reducing the complexity of integration. By facilitating clear communication between senders and receivers, they deliver a safe, reliable and user-friendly experience for online payments +- **Admin APIs:** Empowering you with the tools to take control. The Backend Admin API allows you to oversee critical operational aspects of your Rafiki instance, such as network relationships, assets, account configurations and liquidity. The Auth Admin API offers detailed oversight of grants, providing visibility into their status, associated accounts and permissions, while enabling key management actions, including revocation. +- **Rafiki Admin UI:** The Rafiki Admin application is a user-friendly interface designed to streamline the management of your Rafiki operations. It features a comprehensive dashboard for overseeing peers, assets, wallet addresses, liquidity, webhooks, and payments, serving as an intuitive front–end to Rafiki’s backend service. Additionally, Rafiki supports an optional integration with open-source identity & user management system [Ory Kratos](https://www.ory.sh/kratos/), allowing you to invite or remove users as needed. + ![Rafiki Admin UI](/developers/img/blog/2024-12-11/rafiki-admin.png) + ![Rafiki Admin UI - Payments](/developers/img/blog/2024-12-11/admin-ui-payments.png) +- **Security audit fixes:** Rafiki underwent its first comprehensive [security audit](https://interledger.org/developers/blog/rafikis-first-security-audit/), conducted by an external security firm to identify and address vulnerabilities. Key improvements include implementing HMAC signing for API requests, disabling GraphQL introspection in production, adding protections against denial-of-service (DoS) attacks, and preventing clickjacking in the Admin UI. Proactive dependency scanning was also integrated into the CI pipeline to mitigate library vulnerabilities. This external audit ensures a robust and secure foundation for Rafiki. Security is not a one-time effort; it is an ongoing commitment. As Rafiki evolves, we will continue conducting regular audits and proactively strengthening its defenses to maintain the highest standard of safety and trustworthiness. +- **Telemetry:** Gain real-time insights to understand and optimize your deployments. Rafiki’s telemetry captures key metrics, including the number of packets flowing through the system, the number of transactions, the total value sent through the network, as well as the average transaction value and time - all while preserving user privacy. [Check telemetry in action](https://rafikitelemetry.grafana.net/public-dashboards/f70c8a6033b14da5a9f1cb974def602a). + ![Telemetry](/developers/img/blog/2024-12-11/telemetry.png) +- **New documentation:** Clear, concise, and crafted with precision, Rafiki’s [new documentation](https://rafiki.dev) is designed to empower integrators, developers and administrators alike. We understand that great tools need great instructions and our updated documentation reflects this philosophy. By making our documentation more accessible, detailed and actionable, we are ensuring that Rafiki is not only powerful but also easy to adopt and extend ## What comes next? + The journey does not end here; in fact, it begins anew. In the months ahead, we will focus on: -* **Performance Improvements:** Rethinking architecture for even greater efficiency. -* **Multi-hop Functionality:** Expanding Rafiki’s reach by enabling payments to traverse multiple nodes in the network. This feature allows for greater flexibility, as payments can flow across intermediary connectors to reach their destination, even when direct paths do not exist. Multi-hop functionality is key to creating a truly interconnected and scalable payment network. -* **Multi-tenancy Support:** Enabling a single instance of Rafiki software to service multiple account servicing entities (aka tenants). Each tenant operates independently with isolated configurations, data and resources, ensuring security and privacy while sharing the underlying infrastructure. A single Rafiki deployment could simultaneously support multiple digital wallet providers, each with their own branching, users and payment configurations, all while leveraging the same core system. This makes it easier for organizations to scale operations, reduce costs and support diverse business models within a unified environment. +- **Performance Improvements:** Rethinking architecture for even greater efficiency. +- **Multi-hop Functionality:** Expanding Rafiki’s reach by enabling payments to traverse multiple nodes in the network. This feature allows for greater flexibility, as payments can flow across intermediary connectors to reach their destination, even when direct paths do not exist. Multi-hop functionality is key to creating a truly interconnected and scalable payment network. +- **Multi-tenancy Support:** Enabling a single instance of Rafiki software to service multiple account servicing entities (aka tenants). Each tenant operates independently with isolated configurations, data and resources, ensuring security and privacy while sharing the underlying infrastructure. A single Rafiki deployment could simultaneously support multiple digital wallet providers, each with their own branching, users and payment configurations, all while leveraging the same core system. This makes it easier for organizations to scale operations, reduce costs and support diverse business models within a unified environment. ## Reflecting on the journey + Let’s take a moment to reflect on the significance of this Beta release. Rafiki Beta is more than just a set of features. It represents what can be achieved when a global community unites around a common vision. It stands as a proof that open payments can be secure, scalable and accessible to all. The journey here hasn’t been without its challenges. From feature creep to overcoming performance bottlenecks, we have faced numerous hurdles. Yet, each challenge has been an opportunity to learn, improve and create something stronger. @@ -58,6 +61,7 @@ The journey here hasn’t been without its challenges. From feature creep to ove At the recent [Interledger Summit in Cape Town](https://interledger.org/summit), the impact of our efforts was clear. From live demonstrations of the newly rebranded [Test Wallet](https://wallet.interledger-test.dev), to integrations with partners like [People’s Clearinghouse](https://lacamara.mx) and [GateHub](https://gatehub.net), Rafiki’s potential was on full display. It was a moment of pride, a reminder of our purpose, and a glimpse into the promising future we are building together. ## Join us in the future of Open Payments + Our journey is far from complete. Now, we extend an invitation to you - our community, partners, and collaborators, to join us in the next chapter of this endeavour. Whether you are building integrations, testing performance, or simply exploring Rafiki’s capabilities, you are an integral part of this story. Together, we can create a world where payments flow as seamlessly as ideas and financial inclusion becomes more than just a goal - it becomes a reality. Together, we can make sending payments as simple as sending an email. diff --git a/src/content/config.ts b/src/content/config.ts deleted file mode 100644 index 228f976..0000000 --- a/src/content/config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { z, defineCollection } from "astro:content"; -import { docsSchema, i18nSchema } from "@astrojs/starlight/schema"; - -const blogCollection = defineCollection({ - type: "content", - schema: z.object({ - title: z.string(), - description: z.string(), - date: z.date(), - image: z.string().optional(), - tags: z.array(z.string()), - }), -}); - -export const collections = { - docs: defineCollection({ schema: docsSchema() }), - i18n: defineCollection({ type: "data", schema: i18nSchema() }), - blog: blogCollection, -}; diff --git a/src/layouts/BlogLayout.astro b/src/layouts/BlogLayout.astro index 38a348d..edc2cc0 100644 --- a/src/layouts/BlogLayout.astro +++ b/src/layouts/BlogLayout.astro @@ -209,4 +209,8 @@ article :global(code) { padding: 0.125rem 0.375rem; overflow-wrap: anywhere; } + +article :global(ul li) { + margin-block-end: var(--space-2xs); +} diff --git a/src/pages/blog/[...id].astro b/src/pages/blog/[...id].astro new file mode 100644 index 0000000..af31512 --- /dev/null +++ b/src/pages/blog/[...id].astro @@ -0,0 +1,21 @@ +--- +import { getCollection, render } from 'astro:content'; +import BlogLayout from '../../layouts/BlogLayout.astro'; +import CommunityLinks from "../../components/blog/CommunityLinks.astro"; + +export async function getStaticPaths() { + const posts = await getCollection('blog'); + return posts.map(post => ({ + params: { id: post.id }, + props: { post }, + })); +} + +const { post } = Astro.props; +const { Content } = await render(post); +--- + + + + + diff --git a/src/pages/blog/[...page].astro b/src/pages/blog/[...page].astro index f53442a..ac72b5d 100644 --- a/src/pages/blog/[...page].astro +++ b/src/pages/blog/[...page].astro @@ -2,6 +2,7 @@ import type { Page } from "astro"; import { createExcerpt } from '../../utils/create-excerpt'; import BaseLayout from '../../layouts/BaseLayout.astro'; +import Pagination from '../../components/blog/Pagination.astro'; import { getCollection } from 'astro:content'; type Props = { @@ -9,8 +10,8 @@ type Props = { }; export async function getStaticPaths({ paginate }: any) { - const blogEntries = (await getCollection("blog")).sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); - return paginate(blogEntries, { pageSize: 12 }); + const blogEntries = (await getCollection("blog")).sort((a:any, b:any) => b.data.date.getTime() - a.data.date.getTime()); + return paginate(blogEntries, { pageSize: 10 }); } const { page } = Astro.props; @@ -41,12 +42,19 @@ const { page } = Astro.props; - {blogPostEntry.data.title} + {blogPostEntry.data.title}

{blogPostEntry.data.description ? blogPostEntry.data.description : excerpt}

)} )} + diff --git a/src/pages/blog/[...slug].astro b/src/pages/blog/[...slug].astro deleted file mode 100644 index 17ccd61..0000000 --- a/src/pages/blog/[...slug].astro +++ /dev/null @@ -1,14 +0,0 @@ ---- -import { getCollection } from 'astro:content'; - -export async function getStaticPaths() { - const blogEntries = await getCollection('blog'); - return blogEntries.map(entry => ({ - params: { slug: entry.slug }, props: { entry }, - })); -} - -const { entry } = Astro.props; -const { Content } = await entry.render(); ---- -