mirror of
https://github.com/tcsenpai/timecapsule.git
synced 2025-06-02 17:30:21 +00:00
first draft
This commit is contained in:
commit
4294c61003
177
.gitignore
vendored
Normal file
177
.gitignore
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||
|
||||
# Logs
|
||||
|
||||
logs
|
||||
_.log
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Caches
|
||||
|
||||
.cache
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
||||
yarn.lock
|
||||
package-lock.json
|
35
README.md
Normal file
35
README.md
Normal file
@ -0,0 +1,35 @@
|
||||
# timecapsule
|
||||
A for-fun digital time capsule that does not need a cloud service and can run everywhere.
|
||||
|
||||
## What is this
|
||||
Let's say you want to write a message to your future self, or you want to leave a funny riddle to your descendants.
|
||||
Let's say you don't trust anybody other than yourself.
|
||||
You can use timecapsule to achieve this!
|
||||
|
||||
Basically, you can encrypt a message with a password and specify an "opening date".
|
||||
As the date is hashed with your password and used to encrypt the message, that message can be opened only on that precise date (and with that specific password).
|
||||
|
||||
## Disclaimer
|
||||
This is a for-fun project and has no claims regarding security whatsoever. It is very simple to circumvent the mechanism by, for example, spoofing the "right date". Technically, though, if the receiver does not know the date, it should be hard to spoof it. It would make the time capsule not very useful too, though.
|
||||
|
||||
See it as a funny riddle or funny game.
|
||||
|
||||
## Usage
|
||||
|
||||
See index.ts, the working code is there.
|
||||
|
||||
## Installation
|
||||
|
||||
To install dependencies:
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
To run:
|
||||
|
||||
```bash
|
||||
tsx index.ts
|
||||
```
|
24
index.ts
Normal file
24
index.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import type timeKey from "./libs/types/timeKey"
|
||||
import { timeEncrypt, timeDecrypt } from "./libs/Encryption";
|
||||
|
||||
async function main() {
|
||||
// We set our secret and passwords here
|
||||
let secret = "secret";
|
||||
let password = "password";
|
||||
// We want this to be opened only this day
|
||||
let proposedTimeKey: timeKey = {
|
||||
time: {
|
||||
day: 29,
|
||||
month: 3,
|
||||
year: 2024,
|
||||
},
|
||||
password: ""
|
||||
}
|
||||
// Testing
|
||||
let enc = await timeEncrypt(secret, password, proposedTimeKey);
|
||||
console.log(`Encrypted: ${enc}`);
|
||||
let dec = await timeDecrypt(enc, password);
|
||||
console.log(`Decrypted: ${dec}`);
|
||||
}
|
||||
|
||||
main()
|
39
libs/Encryption.ts
Normal file
39
libs/Encryption.ts
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
// Encryption.ts
|
||||
import timeGet from "./timeGet"
|
||||
import timeKeyHasher from "./timeKeyHasher"
|
||||
import crypto from "crypto"
|
||||
import type timeKey from "./types/timeKey";
|
||||
const algorithm = 'aes-256-ctr';
|
||||
const IV_LENGTH = 16;
|
||||
|
||||
export async function timeEncrypt(text: string, plain_password: string, date: timeKey) {
|
||||
console.log("To be opened on: ")
|
||||
console.log(date)
|
||||
// Getting the timed password and using it to encrypt the text
|
||||
let password = await timeKeyHasher(date, plain_password)
|
||||
// Adding a random iv
|
||||
let iv = crypto.randomBytes(IV_LENGTH);
|
||||
// Ciphering the plain text
|
||||
let cipher = crypto.createCipheriv(algorithm, Buffer.from(password, 'hex'), iv);
|
||||
let encrypted = cipher.update(text);
|
||||
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
||||
return iv.toString('hex') + ':' + encrypted.toString('hex');
|
||||
}
|
||||
|
||||
export async function timeDecrypt(text: string, plain_password: string) {
|
||||
// Getting the timed password and using it to decrypt the text
|
||||
let date = await timeGet()
|
||||
console.log("Today is: ")
|
||||
console.log(date)
|
||||
let password = await timeKeyHasher(date, plain_password)
|
||||
// Separating the iv
|
||||
let textParts = text.split(':');
|
||||
let iv = Buffer.from(textParts.shift() as string, 'hex');
|
||||
let encryptedText = Buffer.from(textParts.join(':'), 'hex');
|
||||
// Deciphering the encrypted text
|
||||
let decipher = crypto.createDecipheriv(algorithm, Buffer.from(password, 'hex'), iv);
|
||||
let decrypted = decipher.update(encryptedText);
|
||||
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||
return decrypted.toString();
|
||||
}
|
17
libs/timeGet.ts
Normal file
17
libs/timeGet.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import type timeKey from "./types/timeKey";
|
||||
import { Client as NTP } from "ntp-time"
|
||||
const ntp_client = new NTP('0.europe.pool.ntp.org', 123, { timeout: 1000 });
|
||||
|
||||
// Get time from NTP and create a timeKey without a password linked
|
||||
export default async function timeGet(): Promise<timeKey>{
|
||||
const ntp = await ntp_client.syncTime();
|
||||
const date = new Date(ntp.time);
|
||||
return {
|
||||
time: {
|
||||
day: date.getDate(),
|
||||
month: date.getMonth() + 1,
|
||||
year: date.getFullYear(),
|
||||
},
|
||||
password: "",
|
||||
} as timeKey;
|
||||
}
|
11
libs/timeKeyHasher.ts
Normal file
11
libs/timeKeyHasher.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import type timeKey from "./types/timeKey";
|
||||
import { sha256digest } from '@digitalcredentials/sha256-universal'
|
||||
|
||||
// Join together a timeKey + a password in a sha256 hash that can be used to encrypt / decrypt data
|
||||
export default async function timeKeyHasher(time: timeKey, password: string): Promise<string> {
|
||||
time.password = password;
|
||||
let timeString = JSON.stringify(time)
|
||||
let timeKeyHash = await sha256digest(timeString);
|
||||
let timeKeyHashHex = Buffer.from(timeKeyHash).toString('hex')
|
||||
return timeKeyHashHex;
|
||||
}
|
8
libs/types/timeKey.ts
Normal file
8
libs/types/timeKey.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export default interface timeKey {
|
||||
time: {
|
||||
day: number;
|
||||
month: number;
|
||||
year: number;
|
||||
}
|
||||
password: string;
|
||||
}
|
17
package.json
Normal file
17
package.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "timecapsule",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"@types/sha256-universal": "^1.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@digitalcredentials/sha256-universal": "^1.1.1",
|
||||
"ntp-time": "^2.0.4",
|
||||
"tsx": "^4.7.1"
|
||||
}
|
||||
}
|
27
tsconfig.json
Normal file
27
tsconfig.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Enable latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user