Skip to content

Commit

Permalink
Merge pull request #9 from TheBlackbird14/better-encryption
Browse files Browse the repository at this point in the history
Better encryption
  • Loading branch information
TheBlackbird14 authored Aug 26, 2024
2 parents 3b1de97 + fa27c3b commit bec5344
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 148 deletions.
4 changes: 2 additions & 2 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import ThemeButton from '@/components/themeButton.vue'
let logged_in = ref(false)
try {
const credentials = storageService.retrieve_credentials()
if (credentials) {
if (storageService.retrieve_username()) {
logged_in = ref(true)
} else {
logged_in = ref(false)
Expand Down
7 changes: 1 addition & 6 deletions src/components/enterLogin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import { ref } from 'vue'
import apiService from '@/scripts/api.service'
import storageService from '@/scripts/storage.service'
const password_visible = ref(false)
const remember = ref(true)
Expand Down Expand Up @@ -47,12 +46,8 @@ function login() {
if (username.value != '' && password.value != '') {
apiService
.load(username.value, password.value)
.login(username.value, password.value, remember.value)
.then(() => {
console.log('login successful')
storageService.store_credentials(username.value, password.value, remember.value)
location.reload()
})
.catch((error) => {
Expand Down
131 changes: 87 additions & 44 deletions src/scripts/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,60 @@ class ApiService {
this.baseUrl = apiUrl
}

async load(username: string, password: string) {
const authorization = await storageService.encryptString(username, password)
async login(username: string, password: string, stayLoggedIn: boolean) {
try {
const response = await fetch(`${this.baseUrl}/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: username,
password: password,
stayLoggedIn: stayLoggedIn
}),
credentials: 'include'
})

if (response.status === 401) {
await this.logout()
location.reload()
}

const data = await response.text()

console.log(data)

} catch (e) {
console.error('Error fetching data: ', e)
throw e
}

}

async logout() {
try {
await fetch(`${this.baseUrl}/logout`, {
method: 'GET',
credentials: 'include'
})
} catch (e) {
console.error('Error logging out: ', e)
throw e
}
}

async load() {

try {
const response = await fetch(`${this.baseUrl}/homework/load`, {
method: 'GET',
headers: {
Authorization: authorization
}
credentials: 'include'
})

if (response.status === 403) {
throw new Error('403')
if (response.status === 401) {
await this.logout()
location.reload()
}
} catch (e) {
console.error('Error fetching data: ', e)
Expand All @@ -31,22 +72,20 @@ class ApiService {
}

async all(): Promise<homework[]> {
const authorization = storageService.retrieve_credentials()

if (authorization === null) {
throw new Error('403')
if (storageService.retrieve_username() === null) {
throw new Error('401')
}

try {
const response = await fetch(`${this.baseUrl}/homework/all`, {
method: 'GET',
headers: {
Authorization: authorization[1]
}
credentials: 'include'
})

if (response.status === 403) {
throw new Error('403')
if (response.status === 401) {
await this.logout()
location.reload()
}

const data: homework[] = await response.json()
Expand Down Expand Up @@ -88,16 +127,14 @@ class ApiService {
storageService.update_homework(id, completed)
}

const authorization = storageService.retrieve_credentials()

if (authorization === null) {
throw new Error('403')
if (storageService.retrieve_username() === null) {
await this.logout()
location.reload()
}

const options = new Headers({
Authorization: authorization[1],
Accept: 'application/json',
'Content-Type': 'application/json'
'Content-Type': 'application/json',
})

try {
Expand All @@ -106,11 +143,13 @@ class ApiService {
headers: options,
body: JSON.stringify({
completed: completed
})
}),
credentials: 'include'
})

if (response.status === 403) {
throw new Error('403')
if (response.status === 401) {
await this.logout()
location.reload()
}
} catch (e) {
console.error('Error fetching data: ', e)
Expand All @@ -123,26 +162,26 @@ class ApiService {
storageService.delete_homework(id)
}

const authorization = storageService.retrieve_credentials()

if (authorization === null) {
throw new Error('403')
if (storageService.retrieve_username() === null) {
await this.logout()
location.reload()
}

const options = new Headers({
Authorization: authorization[1],
Accept: 'application/json',
'Content-Type': 'application/json'
})

try {
const response = await fetch(`${this.baseUrl}/homework/delete/${id}`, {
method: 'GET',
headers: options
headers: options,
credentials: 'include'
})

if (response.status === 403) {
throw new Error('403')
if (response.status === 401) {
await this.logout()
location.reload()
}
} catch (e) {
console.error('Error fetching data: ', e)
Expand All @@ -151,14 +190,14 @@ class ApiService {
}

async createHomework(homework: createHomeworkDto) {
const authorization = storageService.retrieve_credentials()

if (authorization === null) {
throw new Error('403')

if (storageService.retrieve_username() === null) {
await this.logout()
location.reload()
}

const options = new Headers({
Authorization: authorization[1],
'Content-Type': 'application/json'
})

Expand All @@ -171,11 +210,13 @@ class ApiService {
teacher: homework.teacher,
text: homework.text,
dateDue: homework.dateDue
})
}),
credentials: 'include'
})

if (response.status === 403) {
throw new Error('403')
if (response.status === 401) {
await this.logout()
location.reload()
}
} catch (e) {
console.error('Error fetching data: ', e)
Expand All @@ -186,11 +227,13 @@ class ApiService {
async getFood(): Promise<foodScheduleEntry[]> {
try {
const response = await fetch(`${this.baseUrl}/food/latest`, {
method: 'GET'
method: 'GET',
credentials: 'include'
})

if (response.status === 403) {
throw new Error('403')
if (response.status === 401) {
await this.logout()
location.reload()
}

const data: foodScheduleEntry[] = await response.json()
Expand Down Expand Up @@ -218,7 +261,7 @@ class ApiService {
}
}

const apiService = new ApiService('https://api.hausaufgaben.live/api')
// const apiService = new ApiService('http://localhost:3000/api')
// const apiService = new ApiService('https://api.hausaufgaben.live/api')
const apiService = new ApiService('http://localhost:3000/api')

export default apiService
102 changes: 6 additions & 96 deletions src/scripts/storage.service.ts
Original file line number Diff line number Diff line change
@@ -1,96 +1,9 @@
class StorageService {
key = 'Z3bdat/AhyxCaVwoh5nRbwurIRq8hemCK2C4ObIcEEs='

/* mostly ChatGPT bs here, don't judge */

private generateIV(): Uint8Array {
const iv = new Uint8Array(16)
crypto.getRandomValues(iv)
return iv
}

private stringToUint8Array(str: string): Uint8Array {
const encoder = new TextEncoder()
return encoder.encode(str)
}
private base64ToUint8Array(base64: string): Uint8Array {
const binaryString = atob(base64)
const len = binaryString.length
const bytes = new Uint8Array(len)

for (let i = 0; i < len; ++i) {
bytes[i] = binaryString.charCodeAt(i)
}

return bytes
}

private uint8ArrayToHexString(arr: Uint8Array): string {
return Array.from(arr)
.map((byte) => byte.toString(16).padStart(2, '0'))
.join('')
}

async encryptString(username: string, password: string): Promise<string> {
let input = username + ':' + password

input = btoa(input)

const key = await crypto.subtle.importKey(
'raw',
this.base64ToUint8Array(this.key),
{ name: 'AES-CBC', length: 256 },
false,
['encrypt']
)

const iv = this.generateIV()
const encodedInput = this.stringToUint8Array(input)
import apiService from "@/scripts/api.service";

const algorithm: AesCbcParams = { name: 'AES-CBC', iv: iv }
const ciphertext = await crypto.subtle.encrypt(algorithm, key, encodedInput)

// Combine IV and ciphertext into a single Uint8Array
const encryptedBytes = new Uint8Array(iv.length + ciphertext.byteLength)
encryptedBytes.set(iv)
encryptedBytes.set(new Uint8Array(ciphertext), iv.length)

// Convert IV and ciphertext to hex strings
const ivHex = this.uint8ArrayToHexString(iv)
const ciphertextHex = this.uint8ArrayToHexString(new Uint8Array(ciphertext))

// Combine IV and ciphertext hex strings
return ciphertextHex + ivHex
}

/* now the good stuff */

async store_credentials(username: string, password: string, remember: boolean) {
/* removing legacy cookies from old website */
localStorage.removeItem('username')
localStorage.removeItem('password')

const encrypted_credentials = await this.encryptString(username, password)

if (remember) {
localStorage.setItem('username', username)
localStorage.setItem('credentials', encrypted_credentials)
} else {
sessionStorage.setItem('username', username)
sessionStorage.setItem('credentials', encrypted_credentials)
}
}

/* returns [username, credentials] or null */
retrieve_credentials(): [string, string] | null {
const username = localStorage.getItem('username') || sessionStorage.getItem('username')
const credentials = localStorage.getItem('credentials') || sessionStorage.getItem('credentials')

if (username === null || credentials === null) {
return null
} else {
return [username, credentials]
}
class StorageService {
/* returns username or null */
retrieve_username(): string | undefined {
return document.cookie.split('; ').find(row => row.startsWith('username='));
}

async logout() {
Expand All @@ -100,12 +13,9 @@ class StorageService {
localStorage.removeItem(setting)
})

localStorage.removeItem('username')
localStorage.removeItem('credentials')
localStorage.removeItem('homework')

sessionStorage.removeItem('username')
sessionStorage.removeItem('credentials')
await apiService.logout()
}

update_homework(id: number, completed: Boolean) {
Expand Down

0 comments on commit bec5344

Please sign in to comment.