forked from HermanMartinus/horus-webapp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
send.html
147 lines (136 loc) · 7.17 KB
/
send.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>Send password</title>
<script src="helpers.js"></script>
<script src="aes.js"> </script>
<script src="wordlist.js"></script>
</head>
<body>
<main>
<article>
<div class="encrypt">
<h1>Send Password</h1>
<h2>Share passwords securely</h2>
<fieldset>
<div>
<label>Password to share</label>
<input autofocus type="password" id="password" maxlength=500/>
<small onclick="toggleObscured('#password')" class="hide-show">Hide/Show</small>
<button onclick="encrypt()">Share</button>
</div>
</fieldset>
<fieldset class="result" style="display: none;">
<div>
<label>Encrypted url</label>
<input class="url" type="text" readonly />
<button onclick="copy('.encrypt .url')">Copy to clipboard</button>
<br>
<mark>
Valid for the next 10 minutes
</mark>
</div>
</fieldset>
<div class="explainer">
<p>
Passwords are sent as an expiring encryted package that can only be read once.
</p>
<details>
<summary>How it works</summary>
<p >
<ul style="text-align:left">
<li>
The password is encrypted in-browser using 2 related tokens issued by the server <b>(the encrypted password is never sent to the server)</b>.
</li>
<li>
A shareable URL is generated with the encrypted password package as a hash parameter (so it isn't sent to any server) and the first of the two tokens as a query.
</li>
<li>
Once the link is shared with the recipient and they open it a request is made to the token server with the one token from the parameter. This retrieves the second token from the token server and the token pair is used to decrypt the password.
</li>
<li>
When the second token is requested both tokens are deleted from the server meaning the encrypted password can only be decrypted once.
</li>
</ul>
</p>
</details>
</div>
</div>
<div class="decrypt">
<h3>You've been sent a password</h3>
<p class="expiry-info">
<mark>
Valid for 10 minutes
</mark>
<br>
<small>
This password can only be viewed <u>once</u> before being destroyed.
</small>
<br>
<br>
<button onclick="decrypt()">View</button>
</p>
<fieldset class="result" style="display:none">
<label>Password</label>
<input id="decrypted" type="text" readonly/>
<button onclick="copy('#decrypted')">Copy to clipboard</button>
<br>
<mark>This link has been burnt and cannot be viewed again.</mark>
</fieldset>
</div>
</article>
</main>
<footer>
Send passwords securely with <a href="https://horuspass.com/send">Send Password.</a>
</footer>
<script>
const url = new URL(window.location)
const value = window.location.hash.substring(1, 999);
const token = url.searchParams.get("token")
if (value) {
document.querySelector('.encrypt').style.display = 'none'
const expiry = new Date(+token)
if (expiry.getTime() < new Date().getTime()) {
document.querySelector('.expiry-info mark').innerText = "This link has expired"
document.querySelector('.expiry-info small').innerText = "Request a new shared link from the sender"
document.querySelector('.expiry-info button').style.display = "none"
} else {
document.querySelector('.expiry-info mark').innerText =
`This link expires at ${expiry.toLocaleTimeString('en-US', { hour12: true, hour: '2-digit', minute: '2-digit' })}`
}
} else {
document.querySelector('.decrypt').style.display = 'none'
}
function encrypt() {
const password = document.getElementById('password').value
if (!password) return
fetch('https://send-password.yukihira.workers.dev/token')
.then(response=>response.json())
.then(response => {
const key = response.token + response.value
const encrypted = CryptoJS.AES.encrypt(password, key)
const resultDiv = document.querySelector('.encrypt .result')
resultDiv.style.display = "block"
resultDiv.querySelector('.url').value = `${window.location.href}?token=${response.token}#${encrypted}`
})
}
function decrypt() {
fetch(`https://send-password.yukihira.workers.dev/validate?token=${token}`)
.then(response=>response.text())
.then(response => {
const key = token + response
const decrypted = CryptoJS.AES.decrypt(value.replace(' ', '+'), key);
document.getElementById('decrypted').value = decrypted.toString(CryptoJS.enc.Utf8)
document.querySelector('.decrypt .result').style.display = "block"
document.querySelector('.decrypt .expiry-info').style.display = "none"
if (!decrypted.toString(CryptoJS.enc.Utf8)) {
document.querySelector('.decrypt .result').innerHTML = "This link has been burnt."
}
})
}
</script>
</body>
</html>