Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions censor-with-redact/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
6 changes: 6 additions & 0 deletions censor-with-redact/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true
}
37 changes: 37 additions & 0 deletions censor-with-redact/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Censor with Redact Function

This function allows you to redact sensitive information from a provided text string. It uses the Redact API by Pangea to censor the text. You can use this function to ensure any text you process does not unintentionally reveal sensitive or personally identifiable information.

## Environment Variables

To ensure the function operates as intended, ensure the following variables are set:

- **PANGEA_REDACT_TOKEN**: This is your access token for the Pangea Redact API.

## Usage

This function supports two types of requests:

1. **GET Request**

- **Request Type:** GET
- **Response:**
- On success, the function will respond with an HTML page that can be used to enter text and see the redacted result. The HTML file is located in the 'static' folder, and it's named 'index.html'.

2. **Redact Text**

- **Request Type:** POST
- **Body:**
- The plain text string that you want to redact.
- **Response:**
- On success, the function will respond with the text string with sensitive information redacted.

## Front-End Implementation

The function includes a simple front-end HTML page as an example of how you could use the function from a web page. The front-end sends a POST request to the function when the 'Censor' button is clicked, and the result is displayed on the page.

The HTML file (index.html) is located in the 'static' directory. It uses Alpine.js for interactivity and the @appwrite.io/pink CSS framework for styling. The page includes an input field where the user can type a message, a 'Censor' button to submit the message for redaction, and an area to display the redacted message.

## Error Handling

If the required environment variable `PANGEA_REDACT_TOKEN` is not set, the function will throw an error. Similarly, if a POST request is made without any body content, the function will return an HTTP 400 error with the message "Missing body with a prompt.".
64 changes: 64 additions & 0 deletions censor-with-redact/package-lock.json

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

19 changes: 19 additions & 0 deletions censor-with-redact/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "censor-with-redact",
"version": "1.0.0",
"description": "",
"main": "src/main.js",
"type": "module",
"scripts": {
"format": "prettier --write src/**/*.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"prettier": "^3.0.0"
},
"dependencies": {
"undici": "^5.22.1"
}
}
41 changes: 41 additions & 0 deletions censor-with-redact/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

const staticFolder = path.join(__dirname, '../static')

export default async ({ req, res }) => {
const { PANGEA_REDACT_TOKEN } = process.env

if (!PANGEA_REDACT_TOKEN) {
throw new Error('Function is missing required environment variables.')
}

if (req.method === 'GET') {
const html = fs
.readFileSync(path.join(staticFolder, 'index.html'))
.toString()
return res.send(html, 200, { 'Content-Type': 'text/html; charset=utf-8' })
}

if (!req.bodyString) {
return res.send('Missing body with a prompt.', 400)
}

const response = await fetch(`https://redact.aws.eu.pangea.cloud/v1/redact`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${PANGEA_REDACT_TOKEN}`,
},
body: JSON.stringify({
text: req.bodyString,
}),
})

const data = /** @type {*} */ (await response.json())
return res.send(data.result.redacted_text)
}
88 changes: 88 additions & 0 deletions censor-with-redact/static/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Censor with Redact API Demo</title>

<script>
async function onSubmit(message) {
const response = await fetch("/", {
method: "POST",
body: message,
headers: {
"Content-Type": "text/plain",
},
});

const censoredMessage = await response.text();

return censoredMessage;
}
</script>

<script src="//unpkg.com/alpinejs" defer></script>

<link rel="stylesheet" href="https://unpkg.com/@appwrite.io/pink" />
<link rel="stylesheet" href="https://unpkg.com/@appwrite.io/pink-icons" />
</head>
<body>
<main class="main-content">
<div class="top-cover u-padding-block-end-56">
<div class="container">
<div
class="u-flex u-gap-16 u-flex-justify-center u-margin-block-start-16"
>
<h1 class="heading-level-1">Censor with Redact API Demo</h1>
<code class="u-un-break-text"></code>
</div>
<p
class="body-text-1 u-normal u-margin-block-start-8"
style="max-width: 50rem"
>
This is demo application. You can ue this app to ensure
implementation with Redact API works properly. Use input below to
enter text and get censored message as response.
</p>
</div>
</div>
<div
class="container u-margin-block-start-negative-56"
x-data="{ message: '', censoredMessage: '', loading: false }"
>
<div class="card u-flex u-gap-24 u-flex-vertical">
<div class="u-flex u-cross-center u-gap-8">
<div
class="input-text-wrapper is-with-end-button u-width-full-line"
>
<input x-model="message" type="search" placeholder="Message" />
<div class="icon-search" aria-hidden="true"></div>
</div>

<button
class="button"
x-bind:disabled="loading"
x-on:click="async () => { loading = true; censoredMessage = ''; try { censoredMessage = await onSubmit(message) } catch(err) { console.error(err); } finally { loading = false; } }"
>
<span class="text">Censor</span>
</button>
</div>
<template x-if="censoredMessage">
<div class="u-flex u-flex-vertical u-gap-12">
<div class="u-flex u-flex-vertical u-gap-12 card">
<div class="u-flex u-gap-12">
<h5 class="eyebrow-heading-2">Redact API:</h5>
</div>

<div style="overflow-x: hidden; line-break: anywhere">
<p class="u-color-text-gray" x-text="censoredMessage"></p>
</div>
</div>
</div>
</template>
</div>
</div>
</main>
</body>
</html>