feat: change the application to use url hash for the encryption key (#167)

* feat: change the application to use url hash for the encryption key

the application will still support use url params for a while, but will be removed at the 4.0 breaking release

* chore: update the hemmelig.ts file with the output

* chore: bump the version
This commit is contained in:
bjarneo 2023-03-22 07:30:11 +01:00 committed by GitHub
parent f82f3aa1da
commit 4323c6bb6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 70 deletions

8
cli.js
View File

@ -29,15 +29,15 @@ const cli = meow(
Examples Examples
$ hemmelig "my super secret" --password=1337 $ hemmelig "my super secret" --password=1337
[*] Hemmelig.app URL: https://hemmelig.app/secret/myencryptionkey/thesecretid [*] Hemmelig.app URL: https://hemmelig.app/secret/thesecretid#encryption_key=myencryptionkey
# Pipe data to the hemmelig cli # Pipe data to the hemmelig cli
$ cat mysecret.txt | hemmelig $ cat mysecret.txt | hemmelig
[*] Hemmelig.app URL: https://hemmelig.app/secret/myencryptionkey2/thesecretid2 [*] Hemmelig.app URL: https://hemmelig.app/secret/thesecretid2#encryption_key=myencryptionkey2
# Different output # Different output
$ hemmelig "I am secret" -o=json $ hemmelig "I am secret" -o=json
{"encryptionKey":"9LiWq3iMAF0IkQs1tecOxbYKFesEnTN9","secretId":"manageable_CEsgWtxEaNNbwld6PjwyF1bQaiy4jQl9","url":"https://hemmelig.app/secret/9LiWq3iMAF0IkQs1tecOxbYKFesEnTN9/manageable_CEsgWtxEaNNbwld6PjwyF1bQaiy4jQl9"} {"encryptionKey":"9LiWq3iMAF0IkQs1tecOxbYKFesEnTN9","secretId":"manageable_CEsgWtxEaNNbwld6PjwyF1bQaiy4jQl9","url":"https://hemmelig.app/secret/manageable_CEsgWtxEaNNbwld6PjwyF1bQaiy4jQl9#encryption_key=9LiWq3iMAF0IkQs1tecOxbYKFesEnTN9"}
`, `,
{ {
importMeta: { url }, importMeta: { url },
@ -109,7 +109,7 @@ const createSecret = async (data = {}) => {
}; };
const getSecretURL = (encryptionKey, secretId) => const getSecretURL = (encryptionKey, secretId) =>
`${cli.flags.url}/secret/${encryptionKey}/${secretId}`; `${cli.flags.url}/secret/${secretId}#encryption_key=${encryptionKey}`;
const createOutput = (encryptionKey, secretId) => { const createOutput = (encryptionKey, secretId) => {
const url = getSecretURL(encryptionKey, secretId); const url = getSecretURL(encryptionKey, secretId);

View File

@ -1,82 +1,90 @@
const completionSpec: Fig.Spec = { const completionSpec: Fig.Spec = {
"name": "hemmelig", name: 'hemmelig',
"description": "Encrypt text", description: 'Encrypt text',
"args": [ args: [
{ {
"name": "text", name: 'text',
"description": "Text" description: 'Text',
} },
], ],
"options": [ options: [
{ {
"name": ["-t", "--title"], name: ['-t', '--title'],
"description": "The secret title", description: 'The secret title',
"isOptional": true, isOptional: true,
"args": { args: {
"name": "title", name: 'title',
"description": "The secret title" description: 'The secret title',
} },
}, },
{ {
"name": ["-p", "--password"], name: ['-p', '--password'],
"description": "The password to protect the secret", description: 'The password to protect the secret',
"isOptional": true, isOptional: true,
"args": { args: {
"name": "password", name: 'password',
"description": "The password to protect the secret" description: 'The password to protect the secret',
} },
}, },
{ {
"name": ["-l", "--lifetime"], name: ['-l', '--lifetime'],
"description": "The lifetime of the secret", description: 'The lifetime of the secret',
"isOptional": true, isOptional: true,
"args": { args: {
"name": "lifetime", name: 'lifetime',
"description": "The lifetime of the secret" description: 'The lifetime of the secret',
} },
}, },
{ {
"name": ["-m", "--maxViews"], name: ['-m', '--maxViews'],
"description": "The max views of the secret", description: 'The max views of the secret',
"isOptional": true, isOptional: true,
"args": { args: {
"name": "maxViews", name: 'maxViews',
"description": "The max views of the secret" description: 'The max views of the secret',
} },
}, },
{ {
"name": ["-c", "--cidr"], name: ['-c', '--cidr'],
"description": "Provide the IP or CIDR range", description: 'Provide the IP or CIDR range',
"isOptional": true, isOptional: true,
"args": { args: {
"name": "cidr", name: 'cidr',
"description": "Provide the IP or CIDR range" description: 'Provide the IP or CIDR range',
} },
}, },
{ {
"name": ["-e", "--expire"], name: ['-e', '--expire'],
"description": "Burn the secret only after the expire time", description: 'Burn the secret only after the expire time',
"isOptional": true, isOptional: true,
"args": { args: {
"name": "expire", name: 'expire',
"description": "Burn the secret only after the expire time" description: 'Burn the secret only after the expire time',
} },
}, },
{ {
"name": ["-u", "--url"], name: ['-u', '--url'],
"description": "If you have your own instance of the Hemmelig.app", description: 'If you have your own instance of the Hemmelig.app',
"isOptional": true, isOptional: true,
"args": { args: {
"name": "url", name: 'url',
"description": "If you have your own instance of the Hemmelig.app" description: 'If you have your own instance of the Hemmelig.app',
} },
}, },
{ {
"name": "--help", name: ['-o', '--output'],
"description": "Prints help information", description: 'Do you want the output response in yaml or json',
"isOptional": true, isOptional: true,
} args: {
] name: 'output',
description: 'Do you want the output response in yaml or json',
},
},
{
name: '--help',
description: 'Prints help information',
isOptional: true,
},
],
}; };
export default completionSpec; export default completionSpec;

View File

@ -1,6 +1,6 @@
{ {
"name": "hemmelig", "name": "hemmelig",
"version": "4.3.0", "version": "4.4.0",
"description": "Paste a password, secret message or private information", "description": "Paste a password, secret message or private information",
"main": "index.js", "main": "index.js",
"type": "module", "type": "module",

View File

@ -159,6 +159,9 @@ const App = () => {
<Route path="/secret/:encryptionKey/:secretId" exact> <Route path="/secret/:encryptionKey/:secretId" exact>
<Secret /> <Secret />
</Route> </Route>
<Route path="/secret/:secretId" exact>
<Secret />
</Route>
<Route path="/signin" exact> <Route path="/signin" exact>
<SignIn /> <SignIn />
</Route> </Route>

View File

@ -198,7 +198,8 @@ const Home = () => {
const handleFocus = (event) => event.target.select(); const handleFocus = (event) => event.target.select();
const getSecretURL = () => `${window.location.origin}/secret/${encryptionKey}/${secretId}`; const getSecretURL = () =>
`${window.location.origin}/secret/${secretId}#encryption_key=${encryptionKey}`;
const inputReadOnly = !!secretId; const inputReadOnly = !!secretId;

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useParams, Link } from 'react-router-dom'; import { useParams, Link, useLocation } from 'react-router-dom';
import { Button, Group, Container, Textarea, TextInput, Stack, Title, Text } from '@mantine/core'; import { Button, Group, Container, Textarea, TextInput, Stack, Title, Text } from '@mantine/core';
import { import {
@ -19,10 +19,24 @@ import { decrypt } from '../../../shared/helpers/crypto';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
const getEncryptionKeyHash = (hash) => {
const id = '#encryption_key=';
if (!hash || !hash.includes(id)) {
return '';
}
const [_, encryptionKey] = hash.split('#encryption_key=');
return encryptionKey;
};
const Secret = () => { const Secret = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { secretId, encryptionKey = null } = useParams(); const { hash = '' } = useLocation();
const { secretId, encryptionKey = getEncryptionKeyHash(hash) } = useParams();
const [secret, setSecret] = useState(null); const [secret, setSecret] = useState(null);
const [title, setTitle] = useState(null); const [title, setTitle] = useState(null);
const [preventBurn, setPreventBurn] = useState(false); const [preventBurn, setPreventBurn] = useState(false);