|
|
@ -1,22 +1,29 @@ |
|
|
|
import React, { useState } from 'react'; |
|
|
|
import React, { useRef, useState } from 'react'; |
|
|
|
import md5 from 'md5'; |
|
|
|
import randomstring from 'randomstring'; |
|
|
|
import settings from 'electron-settings'; |
|
|
|
import { Button, Form, ControlLabel, Message } from 'rsuite'; |
|
|
|
import axios from 'axios'; |
|
|
|
import setDefaultSettings from '../shared/setDefaultSettings'; |
|
|
|
import { StyledCheckbox, StyledInput } from '../shared/styled'; |
|
|
|
import { |
|
|
|
StyledCheckbox, |
|
|
|
StyledInput, |
|
|
|
StyledInputPicker, |
|
|
|
StyledInputPickerContainer, |
|
|
|
} from '../shared/styled'; |
|
|
|
import { LoginPanel } from './styled'; |
|
|
|
import GenericPage from '../layout/GenericPage'; |
|
|
|
import logo from '../../../assets/icon.png'; |
|
|
|
import { mockSettings } from '../../shared/mockSettings'; |
|
|
|
|
|
|
|
const Login = () => { |
|
|
|
const [serverType, setServerType] = useState('subsonic'); |
|
|
|
const [serverName, setServerName] = useState(''); |
|
|
|
const [userName, setUserName] = useState(''); |
|
|
|
const [password, setPassword] = useState(''); |
|
|
|
const [legacyAuth, setLegacyAuth] = useState(false); |
|
|
|
const [message, setMessage] = useState(''); |
|
|
|
const serverTypePickerRef = useRef(null); |
|
|
|
|
|
|
|
const handleConnect = async () => { |
|
|
|
setMessage(''); |
|
|
@ -50,6 +57,7 @@ const Login = () => { |
|
|
|
|
|
|
|
localStorage.setItem('server', cleanServerName); |
|
|
|
localStorage.setItem('serverBase64', btoa(cleanServerName)); |
|
|
|
localStorage.setItem('serverType', 'subsonic'); |
|
|
|
localStorage.setItem('username', userName); |
|
|
|
localStorage.setItem('password', password); |
|
|
|
localStorage.setItem('salt', salt); |
|
|
@ -57,6 +65,7 @@ const Login = () => { |
|
|
|
|
|
|
|
settings.setSync('server', cleanServerName); |
|
|
|
settings.setSync('serverBase64', btoa(cleanServerName)); |
|
|
|
settings.setSync('serverType', 'subsonic'); |
|
|
|
settings.setSync('username', userName); |
|
|
|
settings.setSync('password', password); |
|
|
|
settings.setSync('salt', salt); |
|
|
@ -64,7 +73,52 @@ const Login = () => { |
|
|
|
|
|
|
|
// Set defaults on login
|
|
|
|
setDefaultSettings(false); |
|
|
|
window.location.reload(); |
|
|
|
}; |
|
|
|
|
|
|
|
const handleConnectJellyfin = async () => { |
|
|
|
setMessage(''); |
|
|
|
const cleanServerName = serverName.replace(/\/$/, ''); |
|
|
|
const deviceId = randomstring.generate({ length: 12, charset: 'alphanumeric' }); |
|
|
|
|
|
|
|
try { |
|
|
|
const { data } = await axios.post( |
|
|
|
`${cleanServerName}/users/authenticatebyname`, |
|
|
|
{ |
|
|
|
Username: userName, |
|
|
|
Pw: password, |
|
|
|
}, |
|
|
|
{ |
|
|
|
headers: { |
|
|
|
'X-Emby-Authorization': `MediaBrowser Client="Sonixd", Device="PC", DeviceId="${deviceId}", Version="0.1.0"`, |
|
|
|
}, |
|
|
|
} |
|
|
|
); |
|
|
|
|
|
|
|
localStorage.setItem('server', cleanServerName); |
|
|
|
localStorage.setItem('serverBase64', btoa(cleanServerName)); |
|
|
|
localStorage.setItem('serverType', 'jellyfin'); |
|
|
|
localStorage.setItem('username', data.User.Id); |
|
|
|
localStorage.setItem('token', data.AccessToken); |
|
|
|
localStorage.setItem('deviceId', deviceId); |
|
|
|
|
|
|
|
settings.setSync('server', cleanServerName); |
|
|
|
settings.setSync('serverBase64', btoa(cleanServerName)); |
|
|
|
settings.setSync('serverType', 'jellyfin'); |
|
|
|
settings.setSync('username', data.User.Id); |
|
|
|
settings.setSync('token', data.AccessToken); |
|
|
|
settings.setSync('deviceId', deviceId); |
|
|
|
} catch (err) { |
|
|
|
if (err instanceof Error) { |
|
|
|
setMessage(`${err.message}`); |
|
|
|
return; |
|
|
|
} |
|
|
|
setMessage('An unknown error occurred'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Set defaults on login
|
|
|
|
setDefaultSettings(false); |
|
|
|
window.location.reload(); |
|
|
|
}; |
|
|
|
|
|
|
@ -78,6 +132,22 @@ const Login = () => { |
|
|
|
<br /> |
|
|
|
{message !== '' && <Message type="error" description={message} />} |
|
|
|
<Form id="login-form" fluid style={{ paddingTop: '20px' }}> |
|
|
|
<StyledInputPickerContainer ref={serverTypePickerRef}> |
|
|
|
<ControlLabel>Server type</ControlLabel> |
|
|
|
<StyledInputPicker |
|
|
|
container={() => serverTypePickerRef.current} |
|
|
|
cleanable={false} |
|
|
|
data={[ |
|
|
|
{ label: 'Subsonic', value: 'subsonic' }, |
|
|
|
{ label: 'Jellyfin', value: 'jellyfin' }, |
|
|
|
]} |
|
|
|
defaultValue="subsonic" |
|
|
|
valueKey="value" |
|
|
|
labelKey="label" |
|
|
|
onChange={(e: 'subsonic' | 'jellyfin') => setServerType(e)} |
|
|
|
/> |
|
|
|
</StyledInputPickerContainer> |
|
|
|
<br /> |
|
|
|
<ControlLabel>Server</ControlLabel> |
|
|
|
<StyledInput |
|
|
|
id="login-servername" |
|
|
@ -103,28 +173,32 @@ const Login = () => { |
|
|
|
onChange={(e: string) => setPassword(e)} |
|
|
|
/> |
|
|
|
<br /> |
|
|
|
<StyledCheckbox |
|
|
|
defaultChecked={ |
|
|
|
process.env.NODE_ENV === 'test' |
|
|
|
? mockSettings |
|
|
|
: Boolean(settings.getSync('legacyAuth')) |
|
|
|
} |
|
|
|
checked={legacyAuth} |
|
|
|
onChange={(_v: any, e: boolean) => { |
|
|
|
settings.setSync('legacyAuth', e); |
|
|
|
setLegacyAuth(e); |
|
|
|
}} |
|
|
|
> |
|
|
|
Legacy auth (plaintext) |
|
|
|
</StyledCheckbox> |
|
|
|
<br /> |
|
|
|
{serverType === 'subsonic' && ( |
|
|
|
<> |
|
|
|
<StyledCheckbox |
|
|
|
defaultChecked={ |
|
|
|
process.env.NODE_ENV === 'test' |
|
|
|
? mockSettings |
|
|
|
: Boolean(settings.getSync('legacyAuth')) |
|
|
|
} |
|
|
|
checked={legacyAuth} |
|
|
|
onChange={(_v: any, e: boolean) => { |
|
|
|
settings.setSync('legacyAuth', e); |
|
|
|
setLegacyAuth(e); |
|
|
|
}} |
|
|
|
> |
|
|
|
Legacy auth (plaintext) |
|
|
|
</StyledCheckbox> |
|
|
|
<br /> |
|
|
|
</> |
|
|
|
)} |
|
|
|
<Button |
|
|
|
id="login-button" |
|
|
|
appearance="primary" |
|
|
|
type="submit" |
|
|
|
color="green" |
|
|
|
block |
|
|
|
onClick={handleConnect} |
|
|
|
onClick={serverType === 'subsonic' ? handleConnect : handleConnectJellyfin} |
|
|
|
> |
|
|
|
Connect |
|
|
|
</Button> |
|
|
|