diff --git a/package.json b/package.json index 3fb0255..808b2e3 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "bootstrap-vue": "^2.15.0", "howler": "^2.2.0", "material-design-icons-iconfont": "^5.0.1", + "md5-es": "1.8.2", "roboto-fontface": "*", "uuid": "^8.2.0", "vue": "^2.6.10", diff --git a/src/auth/Login.vue b/src/auth/Login.vue index 7fad524..22e8e36 100644 --- a/src/auth/Login.vue +++ b/src/auth/Login.vue @@ -49,7 +49,6 @@ export default Vue.extend({ async created() { this.server = await this.$auth.server; this.username = await this.$auth.username; - this.password = await this.$auth.password; const success = await this.$auth.autoLogin(); if (success) { this.$store.commit("setLoginSuccess", { username: this.username}); @@ -61,7 +60,7 @@ export default Vue.extend({ methods: { login() { this.busy = true; - this.$auth.login(this.server, this.username, this.password, this.rememberLogin) + this.$auth.loginWithPassword(this.server, this.username, this.password, this.rememberLogin) .then(() => { this.$store.commit("setLoginSuccess", { username: this.username }); this.$router.push(this.returnTo); diff --git a/src/auth/service.ts b/src/auth/service.ts index 56c08b8..8414d76 100644 --- a/src/auth/service.ts +++ b/src/auth/service.ts @@ -1,35 +1,45 @@ import axios from 'axios'; +import { randomString, md5 } from '@/shared/utils'; export class AuthService { public server: string = ""; public username: string = ""; - public password: string = ""; + public salt: string = ""; + public hash: string = ""; private authenticated: boolean = false; constructor() { this.server = localStorage.getItem("server") || "/api"; this.username = localStorage.getItem("username") || "guest1"; - this.password = localStorage.getItem("password") || ""; + this.salt = localStorage.getItem("salt") || ""; + this.hash = localStorage.getItem("hash") || ""; } private saveSession() { localStorage.setItem("server", this.server); localStorage.setItem("username", this.username); - localStorage.setItem("password", this.password); + localStorage.setItem("salt", this.salt); + localStorage.setItem("hash", this.hash); } async autoLogin(): Promise { if (!this.server || !this.username) { return false; } - return this.login(this.server, this.username, this.password, false) + return this.loginWithHash(this.server, this.username, this.salt, this.hash, false) .then(() => true) .catch(() => false); } - async login(server: string, username: string, password: string, remember: boolean) { - return axios.get(`${server}/rest/ping.view?u=${username}&p=${password}&v=1.15.0&c=app&f=json`) + async loginWithPassword(server: string, username: string, password: string, remember: boolean) { + const salt = randomString(); + const hash = md5(password + salt); + return this.loginWithHash(server, username, salt, hash, remember); + } + + private async loginWithHash(server: string, username: string, salt: string, hash: string, remember: boolean) { + return axios.get(`${server}/rest/ping.view?u=${username}&s=${salt}&t=${hash}&v=1.15.0&c=app&f=json`) .then((response) => { const subsonicResponse = response.data["subsonic-response"]; if (!subsonicResponse || subsonicResponse.status !== "ok") { @@ -39,7 +49,8 @@ export class AuthService { this.authenticated = true; this.server = server; this.username = username; - this.password = password; + this.salt = salt; + this.hash = hash; if (remember) { this.saveSession(); } diff --git a/src/shared/api.ts b/src/shared/api.ts index 754ebd5..748a71a 100644 --- a/src/shared/api.ts +++ b/src/shared/api.ts @@ -16,7 +16,8 @@ export class API { config.params = config.params || {}; config.baseURL = this.auth.server config.params.u = this.auth.username; - config.params.p = this.auth.password; + config.params.s = this.auth.salt; + config.params.t = this.auth.hash; config.params.c = "app"; config.params.f = "json"; config.params.v = "1.15.0"; @@ -255,12 +256,12 @@ export class API { if (!item.coverArt) { return undefined; } - const { server, username, password } = this.auth; - return `${server}/rest/getCoverArt?id=${item.coverArt}&v=1.15.0&u=${username}&p=${password}&c=test&size=300` + const { server, username, salt, hash } = this.auth; + return `${server}/rest/getCoverArt?id=${item.coverArt}&v=1.15.0&u=${username}&s=${salt}&t=${hash}&c=test&size=300` } private getStreamUrl(id: any) { - const { server, username, password } = this.auth; - return `${server}/rest/stream?id=${id}&format=raw&v=1.15.0&u=${username}&p=${password}&c=test&size=300` + const { server, username, salt, hash } = this.auth; + return `${server}/rest/stream?id=${id}&format=raw&v=1.15.0&u=${username}&s=${salt}&t=${hash}&c=test&size=300` } } diff --git a/src/shared/utils.ts b/src/shared/utils.ts new file mode 100644 index 0000000..3e12aaa --- /dev/null +++ b/src/shared/utils.ts @@ -0,0 +1,13 @@ +import MD5 from 'md5-es'; + +export function randomString(): string { + let arr = new Uint8Array(16); + window.crypto.getRandomValues(arr); + const validChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + arr = arr.map(x => validChars.charCodeAt(x % validChars.length)); + return String.fromCharCode.apply(null, Array.from(arr)); +} + +export function md5(str: string): string { + return MD5.hash(str); +} diff --git a/src/shims-vue.d.ts b/src/shims-vue.d.ts index d9f24fa..a447dbd 100644 --- a/src/shims-vue.d.ts +++ b/src/shims-vue.d.ts @@ -2,3 +2,5 @@ declare module '*.vue' { import Vue from 'vue' export default Vue } + +declare module "md5-es"; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 38f4418..a03aac2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5081,6 +5081,11 @@ material-design-icons-iconfont@^5.0.1: resolved "https://registry.yarnpkg.com/material-design-icons-iconfont/-/material-design-icons-iconfont-5.0.1.tgz#371875ed7fe9c8c520bc7123c3231feeab731c31" integrity sha512-Xg6rIdGrfySTqiTZ6d+nQbcFepS6R4uKbJP0oAqyeZXJY/bX6mZDnOmmUJusqLXfhIwirs0c++a6JpqVa8RFvA== +md5-es@1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/md5-es/-/md5-es-1.8.2.tgz#4c3d07b3f8e70669afd00ba3ac8b4b619741b506" + integrity sha512-LKq5jmKMhJYhsBFUh2w+J3C4bMiC5uQie/UYJ429UATmMnFr6iANO2uQq5HXAZSIupGp0WO2mH3sNfxR4XO40Q== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"