use salt + md5 hash mode instead of plain text password
This commit is contained in:
		
							parent
							
								
									9feae7ed44
								
							
						
					
					
						commit
						ec42ea82eb
					
				| @ -13,6 +13,7 @@ | |||||||
|     "bootstrap-vue": "^2.15.0", |     "bootstrap-vue": "^2.15.0", | ||||||
|     "howler": "^2.2.0", |     "howler": "^2.2.0", | ||||||
|     "material-design-icons-iconfont": "^5.0.1", |     "material-design-icons-iconfont": "^5.0.1", | ||||||
|  |     "md5-es": "1.8.2", | ||||||
|     "roboto-fontface": "*", |     "roboto-fontface": "*", | ||||||
|     "uuid": "^8.2.0", |     "uuid": "^8.2.0", | ||||||
|     "vue": "^2.6.10", |     "vue": "^2.6.10", | ||||||
|  | |||||||
| @ -49,7 +49,6 @@ export default Vue.extend({ | |||||||
|   async created() { |   async created() { | ||||||
|     this.server = await this.$auth.server; |     this.server = await this.$auth.server; | ||||||
|     this.username = await this.$auth.username; |     this.username = await this.$auth.username; | ||||||
|     this.password = await this.$auth.password; |  | ||||||
|     const success = await this.$auth.autoLogin(); |     const success = await this.$auth.autoLogin(); | ||||||
|     if (success) { |     if (success) { | ||||||
|       this.$store.commit("setLoginSuccess", { username: this.username}); |       this.$store.commit("setLoginSuccess", { username: this.username}); | ||||||
| @ -61,7 +60,7 @@ export default Vue.extend({ | |||||||
|   methods: { |   methods: { | ||||||
|     login() { |     login() { | ||||||
|       this.busy = true; |       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(() => { |         .then(() => { | ||||||
|           this.$store.commit("setLoginSuccess", { username: this.username }); |           this.$store.commit("setLoginSuccess", { username: this.username }); | ||||||
|           this.$router.push(this.returnTo); |           this.$router.push(this.returnTo); | ||||||
|  | |||||||
| @ -1,35 +1,45 @@ | |||||||
| import axios from 'axios'; | import axios from 'axios'; | ||||||
|  | import { randomString, md5 } from '@/shared/utils'; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| export class AuthService { | export class AuthService { | ||||||
|   public server: string = ""; |   public server: string = ""; | ||||||
|   public username: string = ""; |   public username: string = ""; | ||||||
|   public password: string = ""; |   public salt: string = ""; | ||||||
|  |   public hash: string = ""; | ||||||
|   private authenticated: boolean = false; |   private authenticated: boolean = false; | ||||||
| 
 | 
 | ||||||
|   constructor() { |   constructor() { | ||||||
|     this.server = localStorage.getItem("server") || "/api"; |     this.server = localStorage.getItem("server") || "/api"; | ||||||
|     this.username = localStorage.getItem("username") || "guest1"; |     this.username = localStorage.getItem("username") || "guest1"; | ||||||
|     this.password = localStorage.getItem("password") || ""; |     this.salt = localStorage.getItem("salt") || ""; | ||||||
|  |     this.hash = localStorage.getItem("hash") || ""; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private saveSession() { |   private saveSession() { | ||||||
|     localStorage.setItem("server", this.server); |     localStorage.setItem("server", this.server); | ||||||
|     localStorage.setItem("username", this.username); |     localStorage.setItem("username", this.username); | ||||||
|     localStorage.setItem("password", this.password); |     localStorage.setItem("salt", this.salt); | ||||||
|  |     localStorage.setItem("hash", this.hash); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async autoLogin(): Promise<boolean> { |   async autoLogin(): Promise<boolean> { | ||||||
|     if (!this.server || !this.username) { |     if (!this.server || !this.username) { | ||||||
|       return false; |       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) |       .then(() => true) | ||||||
|       .catch(() => false); |       .catch(() => false); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async login(server: string, username: string, password: string, remember: boolean) { |   async loginWithPassword(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`) |     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) => { |       .then((response) => { | ||||||
|         const subsonicResponse = response.data["subsonic-response"]; |         const subsonicResponse = response.data["subsonic-response"]; | ||||||
|         if (!subsonicResponse || subsonicResponse.status !== "ok") { |         if (!subsonicResponse || subsonicResponse.status !== "ok") { | ||||||
| @ -39,7 +49,8 @@ export class AuthService { | |||||||
|         this.authenticated = true; |         this.authenticated = true; | ||||||
|         this.server = server; |         this.server = server; | ||||||
|         this.username = username; |         this.username = username; | ||||||
|         this.password = password; |         this.salt = salt; | ||||||
|  |         this.hash = hash; | ||||||
|         if (remember) { |         if (remember) { | ||||||
|           this.saveSession(); |           this.saveSession(); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -16,7 +16,8 @@ export class API { | |||||||
|       config.params = config.params || {}; |       config.params = config.params || {}; | ||||||
|       config.baseURL = this.auth.server |       config.baseURL = this.auth.server | ||||||
|       config.params.u = this.auth.username; |       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.c = "app"; | ||||||
|       config.params.f = "json"; |       config.params.f = "json"; | ||||||
|       config.params.v = "1.15.0"; |       config.params.v = "1.15.0"; | ||||||
| @ -255,12 +256,12 @@ export class API { | |||||||
|     if (!item.coverArt) { |     if (!item.coverArt) { | ||||||
|       return undefined; |       return undefined; | ||||||
|     } |     } | ||||||
|     const { server, username, password } = this.auth; |     const { server, username, salt, hash } = this.auth; | ||||||
|     return `${server}/rest/getCoverArt?id=${item.coverArt}&v=1.15.0&u=${username}&p=${password}&c=test&size=300` |     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) { |   private getStreamUrl(id: any) { | ||||||
|     const { server, username, password } = this.auth; |     const { server, username, salt, hash } = this.auth; | ||||||
|     return `${server}/rest/stream?id=${id}&format=raw&v=1.15.0&u=${username}&p=${password}&c=test&size=300` |     return `${server}/rest/stream?id=${id}&format=raw&v=1.15.0&u=${username}&s=${salt}&t=${hash}&c=test&size=300` | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								src/shared/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/shared/utils.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								src/shims-vue.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								src/shims-vue.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -2,3 +2,5 @@ declare module '*.vue' { | |||||||
|   import Vue from 'vue' |   import Vue from 'vue' | ||||||
|   export default Vue |   export default Vue | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | declare module "md5-es"; | ||||||
| @ -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" |   resolved "https://registry.yarnpkg.com/material-design-icons-iconfont/-/material-design-icons-iconfont-5.0.1.tgz#371875ed7fe9c8c520bc7123c3231feeab731c31" | ||||||
|   integrity sha512-Xg6rIdGrfySTqiTZ6d+nQbcFepS6R4uKbJP0oAqyeZXJY/bX6mZDnOmmUJusqLXfhIwirs0c++a6JpqVa8RFvA== |   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: | md5.js@^1.3.4: | ||||||
|   version "1.3.5" |   version "1.3.5" | ||||||
|   resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" |   resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user