Skip to content

Commit

Permalink
feat: add encrypt and decrypt functions (#679)
Browse files Browse the repository at this point in the history
  • Loading branch information
aralroca authored Dec 13, 2024
1 parent 2b6554c commit de67cbc
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 4 deletions.
2 changes: 2 additions & 0 deletions docs/api-reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ The Brisa API reference is divided into the following sections:
- [`fileSystemRouter`](/api-reference/server-apis/fileSystemRouter)
- [`Initator`](/api-reference/server-apis/Initiator)
- [`serve`](/api-reference/server-apis/serve)
- [`encrypt`](/api-reference/server-apis/encrypt)
- [`decrypt`](/api-reference/server-apis/decrypt)
- [`SSRWebComponent`](/api-reference/server-apis/SSRWebComponent)
- Node.js APIs
- [`serve`](/api-reference/server-apis/node/serve)
Expand Down
34 changes: 34 additions & 0 deletions docs/api-reference/server-apis/decrypt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
description: The `encrypt` function allows you to securely send sensitive data from the client to the server
---

# `decrypt`

## Reference

### `decrypt(encryptedString: string): unknown`

The `decrypt` function allows you to securely retrieve sensitive data sent from the client to the server. It works in conjunction with the [`encrypt`](/api-reference/server-apis/encrypt) function to ensure safe handling of sensitive information.

Converts an encrypted string back into its original text or object, enabling secure client-server communication.

## Example usage:

```tsx 8
import { encrypt, decrypt } from "brisa/server";

// ...
<button
onClick={(e: Event) => {
// Decrypt on the server action:
console.log(
decrypt((e.target as HTMLButtonElement).dataset.encrypted!)
)
}}
data-encrypted={encrypt("some sensible data")}
>
Click to recover sensible data on the server
</button>
```

In this example, the [`encrypt`](/api-reference/server-apis/encrypt) function secures the data before it is stored in a `data-encrypted` attribute. The `decrypt` function is then used on the server to recover the original value.
34 changes: 34 additions & 0 deletions docs/api-reference/server-apis/encrypt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
description: The `encrypt` function allows you to securely send sensitive data from the client to the server
---

# `encrypt`

## Reference

### `encrypt(textOrObject: unknown): string`

The `encrypt` function allows you to securely send sensitive data from the client to the server. It is typically used in conjunction with the [`decrypt`](/api-reference/server-apis/decrypt) function to safely handle data transmission.

Converts a given text or object into an encrypted string for secure client-server communication.

## Example usage:

```tsx 11
import { encrypt, decrypt } from "brisa/server";

// ...
<button
onClick={(e: Event) => {
// Decrypt on the server action:
console.log(
decrypt((e.target as HTMLButtonElement).dataset.encrypted!)
)
}}
data-encrypted={encrypt("some sensible data")}
>
Click to recover sensible data on the server
</button>
```

In this example, the `encrypt` function secures the data before it is stored in a `data-encrypted` attribute. The [`decrypt`](/api-reference/server-apis/decrypt) function is then used on the server to recover the original value.
21 changes: 21 additions & 0 deletions docs/building-your-application/data-management/server-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,25 @@ You can use [`data-` attributes](https://developer.mozilla.org/en-US/docs/Learn/
/>
```

You also can [`encrypt`](/api-reference/server-apis/encrypt) / [`decrypt`](/api-reference/server-apis/decrypt) sensivle data using `data-attributes`:

```tsx
import { encrypt, decrypt } from "brisa/server";

// ...
<button
onClick={(e: Event) => {
// Decrypt on the server action:
console.log(
decrypt((e.target as HTMLButtonElement).dataset.encrypted!)
)
}}
data-encrypted={encrypt("some sensible data")}
>
Click to recover sensible data on the server
</button>
```

### Using the store

You can use the store to transfer data from the client to the server. This is useful when you need to send data that is not in a form.
Expand Down Expand Up @@ -743,6 +762,8 @@ On the client it will always be encrypted and there will be no way to decrypt it
store.get("some-key"); // In the server is automatic decrypted
```

**More**: Take a look also the [`encrypt`](/api-reference/server-apis/encrypt) an [`decrypt`](/api-reference/server-apis/decrypt) functions.

> [!NOTE]
>
> Brisa uses aes-256-cbc for encryption, a combination of cryptographic algorithms used to securely encrypt information recommended by [OpenSSL](https://www.openssl.org/). Encryption keys are generated during the build of your project.
Expand Down
1 change: 1 addition & 0 deletions packages/brisa/src/core/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ export { default as rerenderInAction } from '@/utils/rerender-in-action';
export { getServeOptions } from '@/cli/serve/serve-options';
export { Initiator } from '@/public-constants';
export { fileSystemRouter } from '@/utils/file-system-router';
export { encrypt, decrypt } from '@/utils/crypto';
export { default as serve } from '@/cli/serve/bun-serve';
export const getServer = () => globalThis.brisaServer;
36 changes: 36 additions & 0 deletions packages/brisa/src/types/server.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,42 @@ export type FileSystemRouter = {
match: (routeToMatch: string) => MatchedBrisaRoute | null;
};

/**
* Encrypt sensible data to don't be visible on the client and then recover on a server action:
*
* ```tsx
* <button
* onClick={(e: Event) =>
* console.log(
* decrypt((e.target as HTMLButtonElement).dataset.encrypted)
* )
* }
* data-encrypted={encrypt("hello")}
* >
* Sensible data
* </button>
* ```
*/
export function encrypt(textOrObject: unknown): string;

/**
* Decrypt sensible data on a server action:
*
* ```tsx
* <button
* onClick={(e: Event) =>
* console.log(
* decrypt((e.target as HTMLButtonElement).dataset.encrypted)
* )
* }
* data-encrypted={encrypt("hello")}
* >
* Sensible data
* </button>
* ```
*/
export function decrypt(text: string): unknown;

export function fileSystemRouter(
options: FileSystemRouterOptions,
): FileSystemRouter;
Expand Down
8 changes: 8 additions & 0 deletions packages/www/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,14 @@ export default {
text: 'serve',
link: '/api-reference/server-apis/serve',
},
{
text: 'encrypt',
link: '/api-reference/server-apis/encrypt',
},
{
text: 'decrypt',
link: '/api-reference/server-apis/decrypt',
},
{
text: 'SSRWebComponent',
link: '/api-reference/server-apis/SSRWebComponent',
Expand Down
78 changes: 74 additions & 4 deletions packages/www/src/public/content.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
{
"id": "/api-reference#server-apis",
"title": "Server APIs",
"text": "renderInAction\nrenderToReadableStream\nrenderToString\ngetServeOptions\nfileSystemRouter\nInitator\nserve\nSSRWebComponent\nNode.js APIs\n\nserve\nhandler",
"text": "renderInAction\nrenderToReadableStream\nrenderToString\ngetServeOptions\nfileSystemRouter\nInitator\nserve\nencrypt\ndecrypt\nSSRWebComponent\nNode.js APIs\n\nserve\nhandler",
"titles": [
"API Reference"
]
Expand Down Expand Up @@ -328,7 +328,7 @@
{
"id": "/api-reference/components/request-context#request-context",
"title": "Request Context",
"text": "The RequestContext is a set of utilities provided by Brisa to facilitate the development of server components. It is a Request with some extra functionalities such as managing store, handling context, i18n, and more. import type { RequestContext } from \"brisa\";\n\nexport default function ServerComponent(props, requestContext: RequestContext) {\n const {\n // Shared data across server/web components\n store,\n useContext,\n\n // Useful to control pending state in server components\n indicate,\n\n // Data of the current route\n route,\n\n // Consume translations and control internationalization\n i18n,\n\n // Access to websockets\n ws,\n\n // Get the user IP\n getIp,\n\n // The `finalURL` is the path of your page file\n finalURL,\n\n // Request id\n id,\n\n // The initiator of the request (\"SERVER_ACTION\", \"SPA_NAVIGATION\", \"INITIAL_REQUEST\", \"API_REQUEST\")\n initiator,\n\n // Add styles\n css,\n } = requestContext;\n // ... Server component implementation ...\n} Being an extension of the Request, you also have access to all fields of the Request. In contrast to other frameworks that necessitate imports, our methodology incorporates all these properties directly within each server component.",
"text": "The RequestContext is a set of utilities provided by Brisa to facilitate the development of server components. It is a Request with some extra functionalities such as managing store, handling context, i18n, and more. import type { RequestContext } from \"brisa\";\n\nexport default function ServerComponent(props, requestContext: RequestContext) {\n const {\n // Shared data across server/web components\n store,\n useContext,\n\n // Useful to control pending state in server components\n indicate,\n\n // Data of the current route\n route,\n\n // Consume translations and control internationalization\n i18n,\n\n // Access to websockets\n ws,\n\n // Get the user IP\n getIp,\n\n // The `finalURL` is the path of your page file\n finalURL,\n\n // Request id\n id,\n\n // The initiator of the request (\"SERVER_ACTION\", \"SPA_NAVIGATION\", \"INITIAL_REQUEST\", \"API_REQUEST\")\n initiator,\n\n // Add styles\n css,\n\n // Run tasks after the response is sent\n after,\n } = requestContext;\n // ... Server component implementation ...\n} Being an extension of the Request, you also have access to all fields of the Request. In contrast to other frameworks that necessitate imports, our methodology incorporates all these properties directly within each server component.",
"titles": []
},
{
Expand Down Expand Up @@ -437,6 +437,14 @@
"Request Context"
]
},
{
"id": "/api-reference/components/request-context#after",
"title": "after",
"text": "after(cb: () => void): void The after method allows you to schedule work to be executed after a response (or prerender) is finished. This is useful for tasks and other side effects that should not block the response, such as logging and analytics. It can be used everywhere when you have access to the RequestContext (Middleware, API routes, Server components, etc). Example: import { type RequestContext } from \"brisa\";\n\nexport default function SomeComponent({}, { after }: RequestContext) {\n after(() => {\n console.log(\"The response is sent\");\n });\n\n return <div>Some content</div>;\n} Good to know: after is not a Dynamic API and calling it does not cause a route to become dynamic. If it's used within a static page, the callback will execute at build time.",
"titles": [
"Request Context"
]
},
{
"id": "/api-reference/components/web-context#web-context",
"title": "Web Context",
Expand Down Expand Up @@ -1333,6 +1341,37 @@
"throwable"
]
},
{
"id": "/api-reference/server-apis/decrypt#decrypt",
"title": "decrypt",
"text": "",
"titles": []
},
{
"id": "/api-reference/server-apis/decrypt#reference",
"title": "Reference",
"text": "",
"titles": [
"decrypt"
]
},
{
"id": "/api-reference/server-apis/decrypt#decryptencryptedstring-string-unknown",
"title": "decrypt(encryptedString: string): unknown",
"text": "The decrypt function allows you to securely retrieve sensitive data sent from the client to the server. It works in conjunction with the encrypt function to ensure safe handling of sensitive information. Converts an encrypted string back into its original text or object, enabling secure client-server communication.",
"titles": [
"decrypt",
"Reference"
]
},
{
"id": "/api-reference/server-apis/decrypt#example-usage",
"title": "Example usage:",
"text": "import { encrypt, decrypt } from \"brisa/server\";\n\n// ...\n<button\n onClick={(e: Event) => {\n // Decrypt on the server action:\n console.log(\n decrypt((e.target as HTMLButtonElement).dataset.encrypted!)\n )\n }}\n data-encrypted={encrypt(\"some sensible data\")}\n>\n Click to recover sensible data on the server\n</button> In this example, the encrypt function secures the data before it is stored in a data-encrypted attribute. The decrypt function is then used on the server to recover the original value.",
"titles": [
"decrypt"
]
},
{
"id": "/api-reference/server-apis/deno/handler#handler",
"title": "handler",
Expand Down Expand Up @@ -1411,6 +1450,37 @@
"serve"
]
},
{
"id": "/api-reference/server-apis/encrypt#encrypt",
"title": "encrypt",
"text": "",
"titles": []
},
{
"id": "/api-reference/server-apis/encrypt#reference",
"title": "Reference",
"text": "",
"titles": [
"encrypt"
]
},
{
"id": "/api-reference/server-apis/encrypt#encrypttextorobject-unknown-string",
"title": "encrypt(textOrObject: unknown): string",
"text": "The encrypt function allows you to securely send sensitive data from the client to the server. It is typically used in conjunction with the decrypt function to safely handle data transmission. Converts a given text or object into an encrypted string for secure client-server communication.",
"titles": [
"encrypt",
"Reference"
]
},
{
"id": "/api-reference/server-apis/encrypt#example-usage",
"title": "Example usage:",
"text": "import { encrypt, decrypt } from \"brisa/server\";\n\n// ...\n<button\n onClick={(e: Event) => {\n // Decrypt on the server action:\n console.log(\n decrypt((e.target as HTMLButtonElement).dataset.encrypted!)\n )\n }}\n data-encrypted={encrypt(\"some sensible data\")}\n>\n Click to recover sensible data on the server\n</button> In this example, the encrypt function secures the data before it is stored in a data-encrypted attribute. The decrypt function is then used on the server to recover the original value.",
"titles": [
"encrypt"
]
},
{
"id": "/api-reference/server-apis/fileSystemRouter#filesystemrouter",
"title": "fileSystemRouter",
Expand Down Expand Up @@ -4004,7 +4074,7 @@
{
"id": "/building-your-application/data-management/server-actions#using-data-attributes",
"title": "Using data attributes",
"text": "You can use data- attributes to transfer data from the client to the server. This is useful when you need to send data that is not in a form. <input\n debounceInput={300}\n onInput={(e) => {\n // All this code runs only on the server\n const value = e.target.value;\n\n // Get the value in the server action\n const id = e.target.dataset.id;\n }}\n data-id=\"123\"\n/>",
"text": "You can use data- attributes to transfer data from the client to the server. This is useful when you need to send data that is not in a form. <input\n debounceInput={300}\n onInput={(e) => {\n // All this code runs only on the server\n const value = e.target.value;\n\n // Get the value in the server action\n const id = e.target.dataset.id;\n }}\n data-id=\"123\"\n/> You also can encrypt / decrypt sensivle data using data-attributes: import { encrypt, decrypt } from \"brisa/server\";\n\n// ...\n<button\n onClick={(e: Event) => {\n // Decrypt on the server action:\n console.log(\n decrypt((e.target as HTMLButtonElement).dataset.encrypted!)\n )\n }}\n data-encrypted={encrypt(\"some sensible data\")}\n>\n Click to recover sensible data on the server\n</button>",
"titles": [
"Server Actions",
"Transfer data"
Expand All @@ -4022,7 +4092,7 @@
{
"id": "/building-your-application/data-management/server-actions#transfer-sensitive-data",
"title": "Transfer sensitive data",
"text": "If you want to transfer sensitive data from the render to use it later on the action you can use: store.transferToClient([\"some-key\"], { encrypt: true }); On the client it will always be encrypted and there will be no way to decrypt it, while on the server action you will have access with: store.get(\"some-key\"); // In the server is automatic decrypted Brisa uses aes-256-cbc for encryption, a combination of cryptographic algorithms used to securely encrypt information recommended by OpenSSL. Encryption keys are generated during the build of your project. It is important to note that encryption is a blocking process and may increase the time it takes for the request. It also exposes public data for the server action to access. Before using encrypt, consider if there is a better way to have this data from the action like querying a DB, without the need to expose it in the client.",
"text": "If you want to transfer sensitive data from the render to use it later on the action you can use: store.transferToClient([\"some-key\"], { encrypt: true }); On the client it will always be encrypted and there will be no way to decrypt it, while on the server action you will have access with: store.get(\"some-key\"); // In the server is automatic decrypted More: Take a look also the encrypt an decrypt functions. Brisa uses aes-256-cbc for encryption, a combination of cryptographic algorithms used to securely encrypt information recommended by OpenSSL. Encryption keys are generated during the build of your project. It is important to note that encryption is a blocking process and may increase the time it takes for the request. It also exposes public data for the server action to access. Before using encrypt, consider if there is a better way to have this data from the action like querying a DB, without the need to expose it in the client.",
"titles": [
"Server Actions"
]
Expand Down

0 comments on commit de67cbc

Please sign in to comment.