Skip to content

Commit

Permalink
refactor(login): use custom nuxt auth scheme to handle login
Browse files Browse the repository at this point in the history
This simplifies and fixes a bunch of issues with the login process. All the necessary code is moved
into a custom Nuxt Auth scheme, which handles login exactly how Jellyfin expects it.
UserInit is deprecated and moved to AppInit, which handles all the stuff
that needs initialization on boot.
  • Loading branch information
heyhippari committed Nov 9, 2020
1 parent 591cf8d commit 7585079
Show file tree
Hide file tree
Showing 17 changed files with 15,548 additions and 13,957 deletions.
29,075 changes: 15,311 additions & 13,764 deletions api/api.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion api/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Configuration } from "./configuration";
// @ts-ignore
import globalAxios, { AxiosPromise, AxiosInstance } from 'axios';

export const BASE_PATH = "http://localhost".replace(/\/+$/, "");
export const BASE_PATH = "http://192.168.0.2:8096".replace(/\/+$/, "");

/**
*
Expand Down
26 changes: 21 additions & 5 deletions components/HomeSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

<script lang="ts">
import Vue from 'vue';
import { BaseItemDto } from '../api';
import { BaseItemDto, ImageType } from '../api';
export default Vue.extend({
props: {
Expand Down Expand Up @@ -72,7 +72,11 @@ export default Vue.extend({
limit: 12,
fields: 'PrimaryImageAspectRatio',
imageTypeLimit: 1,
enableImageTypes: 'Primary,Backdrop,Thumb',
enableImageTypes: [
ImageType.Primary,
ImageType.Backdrop,
ImageType.Thumb
],
enableTotalRecordCount: false,
mediaTypes: 'Video'
});
Expand All @@ -86,7 +90,11 @@ export default Vue.extend({
limit: 12,
fields: 'PrimaryImageAspectRatio',
imageTypeLimit: 1,
enableImageTypes: 'Primary,Backdrop,Thumb',
enableImageTypes: [
ImageType.Primary,
ImageType.Backdrop,
ImageType.Thumb
],
enableTotalRecordCount: false,
mediaTypes: 'Audio'
});
Expand All @@ -100,7 +108,11 @@ export default Vue.extend({
limit: 12,
fields: 'PrimaryImageAspectRatio',
imageTypeLimit: 1,
enableImageTypes: 'Primary,Backdrop,Thumb',
enableImageTypes: [
ImageType.Primary,
ImageType.Backdrop,
ImageType.Thumb
],
parentId: this.section.libraryId
});
Expand All @@ -113,7 +125,11 @@ export default Vue.extend({
limit: 12,
fields: 'PrimaryImageAspectRatio',
imageTypeLimit: 1,
enableImageTypes: 'Primary,Backdrop,Thumb',
enableImageTypes: [
ImageType.Primary,
ImageType.Backdrop,
ImageType.Thumb
],
parentId: this.section.libraryId
});
Expand Down
68 changes: 11 additions & 57 deletions components/LoginForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<v-form
ref="form"
v-model="validInputs"
:disabled="loginIn"
:disabled="loading"
@submit.prevent="userLogin"
>
<v-text-field
Expand All @@ -22,7 +22,7 @@
required
></v-text-field>
<v-text-field
v-model="login.pw"
v-model="login.password"
outlined
:label="$t('password')"
:append-icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
Expand All @@ -33,7 +33,7 @@
<v-col class="mr-2">
<v-btn
:disabled="!validInputs"
:loading="loginIn"
:loading="loading"
block
large
color="primary"
Expand All @@ -51,7 +51,6 @@

<script lang="ts">
import Vue from 'vue';
import compareVersions from 'compare-versions';
import { mapActions } from 'vuex';
export default Vue.extend({
Expand All @@ -60,11 +59,11 @@ export default Vue.extend({
serverUrl: '',
login: {
username: '',
pw: ''
password: ''
},
showPassword: false,
validInputs: false,
loginIn: false,
loading: false,
rules: {
serverUrlTest: [
(v: string) => !!v || this.$t('serverAddressRequired'),
Expand All @@ -78,57 +77,12 @@ export default Vue.extend({
...mapActions('user', ['setUser', 'clearUser']),
...mapActions('deviceProfile', ['setDeviceProfile']),
...mapActions('snackbar', ['pushSnackbarMessage']),
async userLogin() {
this.loginIn = true;
try {
this.$axios.setBaseURL(this.serverUrl);
const serverInfo = (await this.$api.system.getPublicSystemInfo()).data;
if (compareVersions.compare(serverInfo.Version || '', '10.7.0', '>=')) {
const response = await this.$auth.loginWith('local', {
data: this.login
});
this.setDeviceProfile();
const accessToken = `MediaBrowser Client="${this.$store.state.deviceProfile.clientName}", Device="${this.$store.state.deviceProfile.deviceName}", DeviceId="${this.$store.state.deviceProfile.deviceId}", Version="${this.$store.state.deviceProfile.clientVersion}", Token="${response.data.AccessToken}"`;
this.$auth.setUserToken(accessToken);
this.$auth.setUser(response.data.User);
this.setUser({
id: response.data.User.Id,
serverUrl: this.serverUrl,
accessToken
});
} else {
this.loginIn = false;
this.pushSnackbarMessage({
message: this.$t('serverVersionTooLow'),
color: 'error'
});
}
} catch (error) {
let errorMessage = this.$t('unexpectedError');
if (!error.response) {
errorMessage = this.$t('serverNotFound');
} else if (
error.response.status === 500 ||
error.response.status === 401
) {
errorMessage = this.$t('incorrectUsernameOrPassword');
} else if (error.response.status === 400) {
errorMessage = this.$t('badRequest');
}
this.loginIn = false;
this.pushSnackbarMessage({
message: errorMessage.toString(),
color: 'error'
});
}
userLogin() {
this.loading = true;
this.setDeviceProfile();
this.$axios.setBaseURL(this.serverUrl);
this.$auth.loginWith('jellyfin', this.login);
this.loading = false;
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion components/Snackbar.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<v-snackbar v-model="model" app :color="color" bottom left>
{{ message }}
{{ $t(message) }}
</v-snackbar>
</template>

Expand Down
1 change: 1 addition & 0 deletions locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"shows": "Shows",
"signIn": "Sign in",
"unexpectedError": "Unexpected error",
"unhandledException": "Unhandled exception",
"upNext": "Up next",
"username": "Username",
"usernameRequired": "Username is required",
Expand Down
51 changes: 8 additions & 43 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ const config: NuxtConfig = {
** https://nuxtjs.org/guide/plugins
*/
plugins: [
// General
'plugins/appInit.ts',
// Components
'plugins/components/vueperSlides.ts',
'plugins/components/vueVirtualScroller.ts',
Expand Down Expand Up @@ -79,7 +81,7 @@ const config: NuxtConfig = {
],
// Doc: https://axios.nuxtjs.org/usage
'@nuxtjs/axios',
'@nuxtjs/auth-next',
'@nuxtjs/auth',
'@nuxtjs/pwa'
],
/*
Expand All @@ -105,48 +107,10 @@ const config: NuxtConfig = {
home: '/'
},
strategies: {
local: {
scheme: 'local',
endpoints: {
login: {
url: '/Users/authenticatebyname',
method: 'post',
propertyName: false,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'X-Emby-Authorization':
'MediaBrowser Client="Jellyfin Web", Device="Firefox", DeviceId="TW96aWxsYS81LjAgKFgxMTsgTGludXggeDg2XzY0OyBydjo3Ny4wKSBHZWNrby8yMDEwMDEwMSBGaXJlZm94Lzc3LjB8MTU5NTQ1MTYzMzE4OQ11", Version="10.7.0"'
}
},
logout: {
url: '/Sessions/Logout',
method: 'post',
propertyName: false,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
},
user: false
},
// TODO: Figure out which token settings are REALLY needed
// FIXME: Duplicate authorization header: "Authorization" and "X-Emby-Authorization"
tokenName: 'X-Emby-Authorization',
tokenType: '',
tokenRequired: true,
globalToken: true,
changeOrigin: true,
autoFetchUser: false,
token: {
type: false
},
refreshToken: {
type: false
}
jellyfin: {
_scheme: '~/schemes/jellyfinScheme'
}
},
plugins: ['plugins/userInit.ts']
}
},
i18n: {
locales: [
Expand Down Expand Up @@ -231,7 +195,8 @@ const config: NuxtConfig = {
]
];
}
}
},
transpile: ['@nuxtjs/auth']
},

/**
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
},
"dependencies": {
"@nuxt/typescript-runtime": "^2.0.0",
"@nuxtjs/auth-next": "^5.0.0-1602966760.822bc05",
"@nuxtjs/auth": "^4.9.1",
"@nuxtjs/axios": "^5.12.0",
"@nuxtjs/pwa": "^3.2.2",
"@types/jest": "^26.0.15",
Expand Down Expand Up @@ -57,6 +57,7 @@
"@nuxtjs/eslint-module": "^3.0.0",
"@nuxtjs/stylelint-module": "^4.0.0",
"@nuxtjs/vuetify": "^1.11.2",
"@types/nuxtjs__auth": "^4.8.5",
"@types/qs": "^6.9.5",
"@vue/test-utils": "^1.1.1",
"babel-core": "7.0.0-bridge.0",
Expand Down
10 changes: 10 additions & 0 deletions plugins/appInit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Plugin } from '@nuxt/types';

const appInitPlugin: Plugin = (context) => {
console.error('setting base url');
if (context.store.state.user.serverUrl) {
context.$axios.setBaseURL(context.store.state.user.serverUrl);
}
};

export default appInitPlugin;
33 changes: 0 additions & 33 deletions plugins/mediaInfoApi.ts

This file was deleted.

21 changes: 0 additions & 21 deletions plugins/userInit.ts

This file was deleted.

Loading

0 comments on commit 7585079

Please sign in to comment.