https://github.com/willswire/store-sentry
Manage access to in-app purchase content hosted in Cloudflare based on App Store Server Notifications
https://github.com/willswire/store-sentry
app-store app-store-server-api cloudflare ios workers
Last synced: 7 months ago
JSON representation
Manage access to in-app purchase content hosted in Cloudflare based on App Store Server Notifications
- Host: GitHub
- URL: https://github.com/willswire/store-sentry
- Owner: willswire
- License: mit
- Created: 2023-05-04T03:02:58.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2023-05-16T14:54:56.000Z (almost 3 years ago)
- Last Synced: 2025-06-26T03:31:15.031Z (8 months ago)
- Topics: app-store, app-store-server-api, cloudflare, ios, workers
- Language: JavaScript
- Homepage:
- Size: 18.6 KB
- Stars: 7
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Absolutely, I can help with that. Here's a draft for the README file of your project.
---
# Store-Sentry
Store-Sentry is a serverless application that allows developers to manage access to in-app purchase content hosted on Cloudflare, based on App Store Server Notifications. The application is structured into two main components: `gatekeeper` and `listening-post`.
## Getting Started
Before setting up Store-Sentry, make sure you have Node.js and npm (Node Package Manager) installed on your machine.
### Prerequisites
- Node.js
- npm (comes with Node.js)
- A Cloudflare account
- Access to the Apple App Store Server Notifications
### Installation
1. Clone the repository
```bash
git clone https://github.com/yourusername/store-sentry.git
```
2. Change the directory
```bash
cd store-sentry
```
3. Install the dependencies
```bash
npm install
```
4. Fill out the necessary environment variables in the `wrangler.toml` files in both `gatekeeper` and `listening-post` directories.
## Usage
Store-Sentry is divided into two components:
1. **gatekeeper**: This component is responsible for managing access to in-app purchase content. It controls the access to both public and premium content based on the user status stored in a key-value pair storage.
2. **listening-post**: This component listens for App Store Server Notifications and updates user access status in the key-value pair storage accordingly.
The two components are independent but work together to manage access to in-app purchase content.
## Contributing
# What this code does:
## Gatekeeper
This code defines two functions, `update` and `read`, and exports an object with a `fetch` method.
The `update` function handles a PUT request. It takes in a `request` object and an `env` object as parameters. It first extracts the search parameters from the request URL and assigns them to `searchParams`. Then, it creates a new URL object from the request URL and assigns it to `url`. It slices the pathname from the URL and assigns it to `fullpath`. It retrieves the value of the "key" parameter from `searchParams` and assigns it to `key`.
If the `key` is equal to the `ADMIN_KEY` stored in the `env` object, it uses the `put` method of `APP_CONTENT` (presumably a storage API) to update the content at the specified `fullpath` with the request body. It returns a response with the message "Updated {fullpath} successfully!".
If the `key` does not match the `ADMIN_KEY`, it returns a response with the message "Forbidden" and a status code of 403.
The `read` function handles a GET request. It takes in a `request` object and an `env` object as parameters. It creates a new URL object from the request URL and assigns it to `url`. It slices the pathname from the URL and assigns it to `fullpath`. It splits the pathname into an array of subpaths using the "/" delimiter and assigns it to `subpaths`.
If the first element of `subpaths` is "public", it uses the `get` method of `APP_CONTENT` to retrieve the content at the specified `fullpath` and assigns it to `plan`.
If the first element of `subpaths` is "premium", it retrieves the "uuid" parameter from the URL search parameters and assigns it to `uuid`. It uses the `get` method of `APP_USERS` to retrieve the status associated with `uuid` and assigns it to `status`. If `status` is "ALLOW", it uses the `get` method of `APP_CONTENT` to retrieve the content at the specified `fullpath` and assigns it to `plan`. If `status` is "DENY", it returns a response with the message "Forbidden" and a status code of 403.
If the first element of `subpaths` is neither "public" nor "premium", it uses the `get` method of `APP_CONTENT` to retrieve the content at the path "inventory.json" and assigns it to `plan`.
Next, the function creates a new Headers object and calls the `writeHttpMetadata` method on `plan` (assuming it's an object with that method) to write the HTTP metadata to the headers. It sets the "etag" header to the HTTP etag of `plan`. Finally, it returns a response with the body of `plan` and the headers.
The exported object has a `fetch` method that takes in a `request`, `env`, and `ctx` as parameters. It uses a switch statement to determine the method of the request. If the method is "PUT", it calls the `update` function with the `request` and `env` parameters. If the method is "GET", it calls the `read` function with the `request` and `env` parameters. Otherwise, it returns a response with the message "Method Not Allowed" and a status code of 405.
## Listening Post
**This code defines several functions that handle an incoming request and perform various operations based on the request's payload. Here's a breakdown of each function and its purpose:**
1. **read**: This function reads the incoming request body and returns a parsed JSON object if the content-type of the request is "application/json". Otherwise, it returns null.
2. **decode**: This function takes a signed payload (assumed to be a JSON web token) and decodes it. It splits the payload by periods, extracts the encoded payload (the second part), and uses the `atob` function to decode the base64-encoded payload. It then parses the decoded payload and returns it as a JSON object.
3. **storeToken**: This function accepts a unique user ID (`uuid`), a notification type, and a subtype. Based on the notification type and subtype, it assigns a verdict ("ALLOW" or "DENY"). The function stores the `uuid` and the verdict in a KV (Key-Value) database.
4. **handle**: This function is the main request handler. It takes an incoming request as a parameter. If the request method is "POST", it reads the request body using the `read` function. If the body contains a "signedPayload" property, it decodes the signed payload using the `decode` function and extracts the notification type, subtype, and data from the payload. If the data includes a "signedTransactionInfo" property, it decodes it and retrieves the `appAccountToken`. The `storeToken` function is then called with the `appAccountToken`, notification type, and subtype to store the token in the KV database. Finally, it returns a new Response with a status of 202 (Accepted).
5. **addEventListener**: This code registers an event listener for the "fetch" event. When a fetch event occurs, it calls the `handle` function with the request and responds with the returned response.
Decodes your JWTs.
Please read [CONTRIBUTING.md](https://github.com/yourusername/store-sentry/blob/main/CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us.
## License
This project is licensed under the MIT License