Proper sessions part 1
[link.git] / www / js / login.js
blobf4af341e8dad9b611d2673dca468f0c6794b0396
1 let browser;
2 if (navigator.userAgent.match(/chrome|chromium|crios/i)) browser = "Chrome"
3 else if (navigator.userAgent.match(/firefox|fxios/i)) browser = "Firefox"
4 else if (navigator.userAgent.match(/safari/i)) browser = "Safari"
5 else if (navigator.userAgent.match(/opr\//i)) browser = "Opera"
6 else if (navigator.userAgent.match(/edg/i)) browser = "Edge"
7 else browser = "Unknown"
8 let os = navigator.platform=="Win32"? "Windows": navigator.platform=="MacIntel"? "Mac": navigator.platform=="Linux"? "Linux": navigator.platform=="Android"? "Android": navigator.platform=="iPhone"? "iOS": navigator.platform=="iPad"? "iOS": navigator.platform=="iPod"? "iOS": "Unknown"
9 // let Request = new XMLHttpRequest()
10 // let Emails = []
11 // let submit = () => {
12 //   if (document.getElementById("email").value == "" && document.getElementById("password").value == "") {
13 //     document.getElementById("error").innerHTML = "Please fill in all fields"
14 //     document.getElementById("email-wrapper").style.border = "1px solid red"
15 //     document.getElementById("password-wrapper").style.border = "1px solid red"
16 //     document.getElementById("email-wrapper").focus()
17 //   } else if (document.getElementById("email").value == "") {
18 //     document.getElementById("error").innerHTML = "Please fill in all fields"
19 //     document.getElementById("email-wrapper").style.border = "1px solid red"
20 //     document.getElementById("email-wrapper").focus()
21 //   } else if (document.getElementById("password").value == "") {
22 //     document.getElementById("error").innerHTML = "Please fill in all fields"
23 //     document.getElementById("password-wrapper").style.border = "1px solid red"
24 //     document.getElementById("email-wrapper").style.border = "1px solid #ccc"
25 //     document.getElementById("password-wrapper").focus()
26 //   } else {
27 //     if (Emails.includes(document.getElementById("email").value)) {
28 //       document.getElementById("error").innerHTML = "You are already logged in with this email!"
29 //       document.getElementById("email-wrapper").style.border = "1px solid red"
30 //       document.getElementById("email-wrapper").focus()
31 //     } else {
32 //       document.getElementById("error").innerHTML = ""
33 //       document.getElementById("email-wrapper").style.border = "1px solid #ccc"
34 //       document.getElementById("password-wrapper").style.border = "1px solid #ccc"
35 //       Request.open("POST", "/api/login", true)
36 //       Request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
37 //       Request.send("email="+document.getElementById("email").value+"&password="+document.getElementById("password").value+"&browser="+browser+"&os="+os)
38 //     }
39 //   }
40 // }
42 // document.getElementById("login").onclick = submit
43 // document.getElementById("email").onkeydown = (e) => { if (e.keyCode == 13) submit() }
44 // document.getElementById("password").onkeydown = (e) => { if (e.keyCode == 13) submit() }
45 // Request.onreadystatechange = () => {
46 //   if (Request.readyState == 4) {
47 //     let Response = JSON.parse(Request.responseText)
48 //     if (Response.Token == undefined) {
49 //       document.getElementById("error").innerHTML = Response.error
50 //       if (Response.error == "Wrong email or password") {
51 //         document.getElementById("email-wrapper").style.border = "1px solid red"
52 //         document.getElementById("password-wrapper").style.border = "1px solid red"
53 //       }
54 //     } else {
55 //       localStorage.getItem("Tokens") == null? localStorage.setItem("Tokens", 1): localStorage.setItem("Tokens", (parseInt(localStorage.getItem("Tokens"))+1))
56 //       localStorage.setItem("Token-"+localStorage.getItem("Tokens"), Response.Token)
57 //       localStorage.setItem("CurrentToken", localStorage.getItem("Tokens"))
58 //       CheckEmails()
59 //       window.location.href = "/"
60 //     }
61 //   }
62 // }
63 // let CheckEmails = () => {
64 //   Emails = []
65 //   let Check = new XMLHttpRequest()
66 //   let Tokens = localStorage.getItem("Tokens")
67 //   if (Tokens != null) {
68 //     for (let i=1;i<=Tokens;i++) {
69 //       Check.open("POST", "/api/user", true)
70 //       Check.setRequestHeader("Authorization", "Bearer "+localStorage.getItem("Token-"+i))
71 //       Check.send()
72 //     }
73 //   }
75 //   Check.onreadystatechange = () => {
76 //     if (Check.readyState == 4) {
77 //       let Response = JSON.parse(Check.responseText)
78 //       if (Response.error == undefined) {
79 //         Emails.push(Response.email)
80 //       }
81 //     }
82 //   }
83 // }
84 // CheckEmails()
96 // New login.js variables
97 let CodeFAType
98 let CodeFAID
99 let CodeFARetry = false
100 let Email
102 // New login.js - Account Selector
103 let LoginPreExisting = i => {
104   window.location.href = "/u/"+i+"/"
107 document.querySelector("#account-select>.button").onclick = () => {
108   document.getElementById("account-select").classList.toggle("hidden")
109   document.getElementById("email").classList.toggle("hidden")
110   document.querySelector("#email>.input>input").focus()
113 // New login.js - Email Input
114 let ErrorEmail = () => {
115   document.querySelector(".input>svg.error").classList.remove("hidden")
116   document.querySelector(".input>svg.success").classList.add("hidden")
117   document.querySelector("#email>a.button").setAttribute("disabled", "")
120 let SuccessEmail = () => {
121   document.querySelector(".input>svg.error").classList.add("hidden")
122   document.querySelector(".input>svg.success").classList.remove("hidden")
123   document.querySelector("#email>a.button").removeAttribute("disabled")
126 document.getElementById("email").onkeyup = () => {
127   let val = document.querySelector("#email>.input>input").value
128   Email = val
129   if (val.length>0 && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val)) SuccessEmail()
130   else ErrorEmail()
133 let EmailNext = () => {
134   let CheckEmail = new XMLHttpRequest()
135   CheckEmail.open("GET", "/api/user/exists?email="+Email, true)
136   CheckEmail.send()
137   CheckEmail.onreadystatechange = () => {
138     if (CheckEmail.readyState == 4 && document.querySelector("#email>.input>input").value == Email && CheckEmail.responseText == "{\"exists\":true}") {
139       document.getElementById("email").classList.toggle("hidden")
140       document.getElementById("password").classList.toggle("hidden")
141       document.querySelector("#email>a.button").removeAttribute("disabled")
142       document.querySelector(".input>svg.error").classList.add("hidden")
143       document.querySelector(".input>svg.success").classList.remove("hidden")
144       document.querySelector("#password>.input>input").focus()
145     } else {
146       document.querySelector(".input>svg.error").classList.remove("hidden")
147       document.querySelector(".input>svg.success").classList.add("hidden")
148       document.querySelector("#email>a.button").setAttribute("disabled", "")
149     }
150   }
153 document.querySelector("#email>.input>input").onkeydown = (e) => { if (e.keyCode == 13) EmailNext() }
154 document.querySelector("#email>a.button").onclick = () => EmailNext()
156 // New login.js - Password Input
157 document.querySelector("#password>div.buttons>a.button-secondary").onclick = () => {
158   document.getElementById("password").classList.toggle("hidden")
159   document.getElementById("email").classList.toggle("hidden")
162 document.querySelector("#password>.input>input").onkeyup = (e) => {
163   let val = document.querySelector("#password>.input>input").value
164   if (val.length>=8 && val.length<=512 && /[\s~`!@#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?()\._]/g.test(val) && /[0-9]/g.test(val)) {
165     document.querySelector("#password>div.buttons>a.button").removeAttribute("disabled")
166   } else {
167     document.querySelector("#password>div.buttons>a.button").setAttribute("disabled", "")
168   }
171 let PasswordLogin = () => {
172   let LoginAttempt = new XMLHttpRequest()
173   LoginAttempt.open("POST", "/api/user/login", true)
174   LoginAttempt.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
175   LoginAttempt.send("email="+Email+"&password="+document.querySelector("#password>.input>input").value+"&browser="+browser+"&os="+os)
176   LoginAttempt.onreadystatechange = () => {
177     if (LoginAttempt.readyState == 4) {
178       console.log(LoginAttempt.responseText)
179       let Response = JSON.parse(LoginAttempt.responseText)
180       if (Response.PhoneNumbers!=undefined&&Response.PhoneNumbers.length>0) {
181         for (let i=0;i<Response.PhoneNumbers.length;i++) {
182           let Selection = document.createElement("div")
183           Selection.classList.add("select")
184           Selection.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1"><path stroke-linecap="round" stroke-linejoin="round" d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z" /></svg><span>'+Response.PhoneNumbers[i][0]+'</span>'
185           Selection.onclick = () => {
186             CodeFAType = "phone"
187             CodeFAID = Response.PhoneNumbers[i][1]
188             document.getElementById("code-fa-select").classList.toggle("hidden")
189             document.getElementById("code-fa").classList.toggle("hidden")
190             console.log(CodeFAID)
191           }
192           document.querySelector("#code-fa-select").appendChild(Selection)
193         }
194         let Back = document.createElement("a")
195         Back.classList.add("button-secondary")
196         Back.innerText = "Back"
197         Back.onclick = () => {
198           document.getElementById("code-fa-select").classList.toggle("hidden")
199           document.getElementById("password").classList.toggle("hidden")
200           let Selections = document.querySelectorAll("#code-fa-select>.select")
201           for (let i=0;i<Selections.length;i++) Selections[i].remove()
202           Back.remove()
203         }
204         document.querySelector("#code-fa-select").appendChild(Back)
205         document.getElementById("password").classList.toggle("hidden")
206         document.getElementById("code-fa-select").classList.toggle("hidden")
207       }
208     }
209   }
212 document.querySelector("#password>div.buttons>.button").onclick = () => PasswordLogin()
213 document.querySelector("#password>.input>input").onkeydown = (e) => { if (e.keyCode == 13) PasswordLogin() }
215 // New login.js - 2FA
216 document.querySelector("#code-fa>div.buttons>a.button-secondary").onclick = () => {
217   document.getElementById("code-fa").classList.toggle("hidden")
218   document.getElementById("code-fa-select").classList.toggle("hidden")
221 let CodeFAWrapper = document.getElementById("code-fa-wrapper")
222 let CodeFA1 = document.getElementById("code-fa-1")
223 let CodeFA2 = document.getElementById("code-fa-2")
224 let CodeFA3 = document.getElementById("code-fa-3")
225 let CodeFA4 = document.getElementById("code-fa-4")
227 let CodeFAError = () => {
228   for (let i=0;i<CodeFAWrapper.childElementCount;i++) CodeFAWrapper.children[i].style.border = "1px solid red"
229   CodeFA4.focus()
232 let CodeFAChange = (now, next) => {
233   if (now.value.length > 1) now.value = now.value[0]
234   if (CodeFA1.value.length == 1 && CodeFA2.value.length == 1 && CodeFA3.value.length == 1 && CodeFA4.value.length == 1) document.getElementById("next").removeAttribute("disabled")
235   else document.getElementById("next").setAttribute("disabled", "")
236   next.focus()
239 let CodeFABackspace = (now, prev, e) => {
240   if (e.keyCode == 8 && now.value.length == 0) {
241     prev.focus()
242     prev.value = ""
243     e.preventDefault()
244   } else if (e.keyCode == 8) {
245     now.value = ""
246     now.focus()
247   }
248   if (CodeFA1.value.length == 0 || CodeFA2.value.length == 0 || CodeFA3.value.length == 0 || CodeFA4.value.length == 0) document.getElementById("next").setAttribute("disabled", "")
251 let CodeFALogin = () => {
252   let LoginAttempt = new XMLHttpRequest()
253   LoginAttempt.open("POST", "/api/user/login", true)
254   LoginAttempt.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
255   LoginAttempt.send("email="+Email+"&password=" + document.querySelector("#password>.input>input").value + "&id=" + CodeFAID + "&code="+CodeFA1.value+CodeFA2.value+CodeFA3.value+CodeFA4.value)
256   console.log("email="+Email+"&password=" + document.querySelector("#password>.input>input").value + "&id=" + CodeFAID + "&code="+CodeFA1.value+CodeFA2.value+CodeFA3.value+CodeFA4.value)
257   LoginAttempt.onreadystatechange = () => {
258     if (LoginAttempt.readyState == 4) {
259       console.log(LoginAttempt.responseText)
260       let Response = JSON.parse(LoginAttempt.responseText)
261       if (Response.error!=undefined) {
262         SentCodeMessage.innerHTML = "We've sent you a new code."
263         document.getElementById("code-fa-error").innerText = "Invalid code."
264         CodeFAError()
265       } else location.href = "/"
266     }
267   }
270 CodeFA1.oninput = () => CodeFAChange(CodeFA1, CodeFA2)
271 CodeFA2.oninput = () => CodeFAChange(CodeFA2, CodeFA3)
272 CodeFA3.oninput = () => CodeFAChange(CodeFA3, CodeFA4)
273 CodeFA4.oninput = () => CodeFAChange(CodeFA4, CodeFA4)
274 CodeFA2.onkeydown = (e) => CodeFABackspace(CodeFA2, CodeFA1, e)
275 CodeFA3.onkeydown = (e) => CodeFABackspace(CodeFA3, CodeFA2, e)
276 CodeFA4.onkeydown = (e) => {
277   CodeFABackspace(CodeFA4, CodeFA3, e)
278   if (e.keyCode == 13) CodeFALogin()
281 document.querySelector("#code-fa>div.buttons>.button").onclick = () => CodeFALogin()
283 let CheckCodeMessage = document.getElementById("check-code")
284 let ResendCodeMessage = document.getElementById("resend-code")
285 let SentCodeMessage = document.getElementById("sent-code")
287 CheckCodeMessage.innerHTML = CheckCodeMessage.innerHTML.replace("{PhoneOrEmail}", CodeFAType == "email"? "email": "phone")
288 ResendCodeMessage.innerHTML = ResendCodeMessage.innerHTML.replace("{PreCodeType}", CodeFAType == "email"? "an": "a")
289 ResendCodeMessage.innerHTML = ResendCodeMessage.innerHTML.replace("{CodeType}", CodeFAType == "email"? "email": "text")
290 SentCodeMessage.innerHTML = SentCodeMessage.innerHTML.replace("{new}", CodeFARetry? "new": "")