diff --git a/ui/package-lock.json b/ui/package-lock.json index ece79a2bd..2415763b7 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -3320,6 +3320,11 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "blueimp-md5": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.12.0.tgz", + "integrity": "sha512-zo+HIdIhzojv6F1siQPqPFROyVy7C50KzHv/k/Iz+BtvtVzSHXiMXOpq2wCfNkeBqdCv+V8XOV96tsEt2W/3rQ==" + }, "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", @@ -10489,6 +10494,14 @@ "object-visit": "^1.0.0" } }, + "md5-hex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-3.0.1.tgz", + "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", + "requires": { + "blueimp-md5": "^2.10.0" + } + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", diff --git a/ui/package.json b/ui/package.json index 66e9e0e79..9ab53e1c5 100644 --- a/ui/package.json +++ b/ui/package.json @@ -7,6 +7,7 @@ "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^8.0.4", "jwt-decode": "^2.2.0", + "md5-hex": "^3.0.1", "prop-types": "^15.7.2", "ra-data-json-server": "^3.1.2", "react": "^16.12.0", diff --git a/ui/src/authProvider.js b/ui/src/authProvider.js index 47b2e579c..3a4e561b4 100644 --- a/ui/src/authProvider.js +++ b/ui/src/authProvider.js @@ -1,4 +1,5 @@ import jwtDecode from 'jwt-decode' +import md5 from 'md5-hex' const authProvider = { login: ({ username, password }) => { @@ -27,6 +28,12 @@ const authProvider = { localStorage.setItem('name', response.name) localStorage.setItem('username', response.username) localStorage.setItem('role', response.isAdmin ? 'admin' : 'regular') + const salt = new Date().getTime().toString() + localStorage.setItem('subsonic-salt', salt) + localStorage.setItem( + 'subsonic-token', + generateSubsonicToken(password, salt) + ) return response }) .catch((error) => { @@ -73,6 +80,12 @@ const removeItems = () => { localStorage.removeItem('username') localStorage.removeItem('role') localStorage.removeItem('version') + localStorage.removeItem('subsonic-salt') + localStorage.removeItem('subsonic-token') +} + +const generateSubsonicToken = (password, salt) => { + return md5(password + salt) } export default authProvider diff --git a/ui/src/player/queue.js b/ui/src/player/queue.js index b56b0ac2b..d4dc882d7 100644 --- a/ui/src/player/queue.js +++ b/ui/src/player/queue.js @@ -5,20 +5,25 @@ const PLAYER_SET_TRACK = 'PLAYER_SET_TRACK' const PLAYER_SYNC_QUEUE = 'PLAYER_SYNC_QUEUE' const PLAYER_SCROBBLE = 'PLAYER_SCROBBLE' +const subsonicUrl = (command, id, options) => { + const username = localStorage.getItem('username') + const token = localStorage.getItem('subsonic-token') + const salt = localStorage.getItem('subsonic-salt') + const timeStamp = new Date().getTime() + const url = `rest/${command}?u=${username}&f=json&v=1.8.0&c=NavidromeUI&t=${token}&s=${salt}&id=${id}&_=${timeStamp}` + if (options) { + return url + '&' + options + } + return url +} + const mapToAudioLists = (item) => ({ id: item.id, name: item.title, singer: item.artist, - cover: `/rest/getCoverArt?u=admin&f=json&v=1.8.0&c=NavidromeUI&size=300&id=${ - item.id - }&jwt=${localStorage.getItem('token')}`, - musicSrc: `/rest/stream?u=admin&f=json&v=1.8.0&c=NavidromeUI&jwt=${localStorage.getItem( - 'token' - )}&id=${item.id}&_=${new Date().getTime()}`, - scrobble: (submit) => - `/rest/scrobble?u=admin&jwt=${localStorage.getItem( - 'token' - )}&f=json&v=1.8.0&c=NavidromeUI&id=${item.id}&submission=${submit}` + cover: subsonicUrl('getCoverArt', item.id), + musicSrc: subsonicUrl('stream', item.id), + scrobble: (submit) => subsonicUrl('scrobble', item.id, `submission=${submit}`) }) const addTrack = (data) => ({