V3-1839 web satellite auth cookie subdomain differentiation (#2601)

* V3-1839 web satellite auth cookie subdomain differentiation
This commit is contained in:
Yehor Butko 2019-07-22 12:46:26 +03:00 committed by GitHub
parent 5b73180f9b
commit 6143be5915
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 133 additions and 123 deletions

View File

@ -66,7 +66,7 @@
import { Component, Vue } from 'vue-property-decorator';
import HeaderedInput from '@/components/common/HeaderedInput.vue';
import Button from '@/components/common/Button.vue';
import { removeToken } from '@/utils/tokenManager';
import { AuthToken } from '@/utils/authToken';
import { APP_STATE_ACTIONS, USER_ACTIONS, NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
import { RequestResponse } from '@/types/response';
@ -102,7 +102,7 @@
}
this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, 'Account was successfully deleted');
removeToken();
AuthToken.remove();
this.isLoading = false;
this.$router.push('/login');

View File

@ -28,7 +28,7 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { removeToken } from '@/utils/tokenManager';
import { AuthToken } from '@/utils/authToken';
import ROUTES from '@/utils/constants/routerConstants';
import {
APP_STATE_ACTIONS,
@ -52,7 +52,7 @@
}
public onLogoutClick(): void {
removeToken();
AuthToken.remove();
this.$router.push(ROUTES.LOGIN.path);
this.$store.dispatch(PM_ACTIONS.CLEAR);

View File

@ -21,7 +21,7 @@ import ProjectDetails from '@/components/project/ProjectDetails.vue';
import ProjectBillingHistory from '@/components/project/billing/BillingArea.vue';
import ProjectPaymentMethods from '@/components/project/ProjectPaymentMethods.vue';
import BucketArea from '@/components/buckets/BucketArea.vue';
import { getToken } from '@/utils/tokenManager';
import { AuthToken } from '@/utils/authToken';
import store from '@/store';
Vue.use(Router);
@ -156,7 +156,7 @@ router.beforeEach((to, from, next) => {
}
if (to.matched.some(route => route.meta.requiresAuth)) {
if (!getToken()) {
if (!AuthToken.get()) {
next(ROUTES.LOGIN);
return;

View File

@ -8,12 +8,12 @@ export class User {
public email: string;
public partnerId: string;
public constructor(fullName: string, shortName: string, email: string, partnerId: string) {
public constructor(fullName: string, shortName: string, email: string, partnerId?: string) {
this.id = '';
this.fullName = fullName;
this.shortName = shortName;
this.email = email;
this.partnerId = partnerId;
this.partnerId = partnerId || '';
}
public getFullName(): string {

View File

@ -5,7 +5,7 @@ import { HttpLink } from 'apollo-link-http';
import ApolloClient from 'apollo-client/ApolloClient';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { setContext } from 'apollo-link-context';
import { getToken } from '@/utils/tokenManager';
import { AuthToken } from '@/utils/authToken';
// Satellite url
const satelliteUrl = new HttpLink({
@ -15,9 +15,9 @@ const satelliteUrl = new HttpLink({
// Adding auth headers
const authLink = setContext((_, {headers}) => {
// get the authentication token from local storage if it exists
const token = getToken();
// return the headers to the context so httpLink can read them
const token = AuthToken.get();
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,

View File

@ -0,0 +1,46 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
// AuthToken exposes methods to manage auth cookie
export class AuthToken {
private static readonly tokenKeySuffix: string = '_tokenKey';
private static tokenKey: string = '_tokenKey';
public static initialize(): void {
AuthToken.tokenKey = (document as any).location.hostname + AuthToken.tokenKeySuffix;
}
public static get(): string {
return AuthToken.getCookie(AuthToken.tokenKey);
}
public static set(tokenValue: string): void {
document.cookie = AuthToken.tokenKey + '=' + tokenValue + '; path=/';
}
public static remove(): void {
document.cookie = AuthToken.tokenKey + '=; path=/';
}
private static getCookie(cname: string): string {
let name: string = cname + '=';
let decodedCookie: string = decodeURIComponent(document.cookie);
let ca: string[] = decodedCookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
}
AuthToken.initialize();

View File

@ -1,36 +0,0 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
const tokenKey: string = 'tokenKey';
export function getToken(): string {
return getCookie(tokenKey);
}
export function setToken(tokenValue: string): void {
document.cookie = tokenKey + '=' + tokenValue + '; path=/';
}
export function removeToken(): void {
document.cookie = tokenKey + '=; path=/';
}
function getCookie(cname: string): string {
let name: string = cname + '=';
let decodedCookie: string = decodeURIComponent(document.cookie);
let ca: string[] = decodedCookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return '';
}

View File

@ -24,7 +24,7 @@ import {AppState} from "../utils/constants/appStateEnum";
import { Component, Vue } from 'vue-property-decorator';
import DashboardHeader from '@/components/header/Header.vue';
import NavigationArea from '@/components/navigation/NavigationArea.vue';
import { removeToken } from '@/utils/tokenManager';
import { AuthToken } from '@/utils/authToken';
import {
API_KEYS_ACTIONS,
APP_STATE_ACTIONS,
@ -50,7 +50,7 @@ import {AppState} from "../utils/constants/appStateEnum";
this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.ERROR);
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, response.errorMessage);
this.$router.push(ROUTES.LOGIN);
removeToken();
AuthToken.remove();
return;
}

View File

@ -4,96 +4,96 @@
<template src="./login.html"></template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HeaderlessInput from '@/components/common/HeaderlessInput.vue';
import Button from '@/components/common/Button.vue';
import { setToken } from '@/utils/tokenManager';
import ROUTES from '@/utils/constants/routerConstants';
import { APP_STATE_ACTIONS, NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
import { getTokenRequest } from '@/api/users';
import { LOADING_CLASSES } from '@/utils/constants/classConstants';
import { AppState } from '@/utils/constants/appStateEnum';
import { validateEmail, validatePassword } from '@/utils/validation';
import EVENTS from '../../utils/constants/analyticsEventNames';
import { Component, Vue } from 'vue-property-decorator';
import HeaderlessInput from '@/components/common/HeaderlessInput.vue';
import Button from '@/components/common/Button.vue';
import { AuthToken } from '@/utils/authToken';
import ROUTES from '@/utils/constants/routerConstants';
import { APP_STATE_ACTIONS, NOTIFICATION_ACTIONS } from '@/utils/constants/actionNames';
import { getTokenRequest } from '@/api/users';
import { LOADING_CLASSES } from '@/utils/constants/classConstants';
import { AppState } from '@/utils/constants/appStateEnum';
import { validateEmail, validatePassword } from '@/utils/validation';
import EVENTS from '../../utils/constants/analyticsEventNames';
@Component({
components: {
HeaderlessInput,
Button
}
})
export default class Login extends Vue {
public forgotPasswordRouterPath: string = ROUTES.FORGOT_PASSWORD.path;
private email: string = '';
private password: string = '';
private loadingClassName: string = LOADING_CLASSES.LOADING_OVERLAY;
private loadingLogoClassName: string = LOADING_CLASSES.LOADING_LOGO;
private emailError: string = '';
private passwordError: string = '';
@Component({
components: {
HeaderlessInput,
Button
}
})
export default class Login extends Vue {
public forgotPasswordRouterPath: string = ROUTES.FORGOT_PASSWORD.path;
private email: string = '';
private password: string = '';
private loadingClassName: string = LOADING_CLASSES.LOADING_OVERLAY;
private loadingLogoClassName: string = LOADING_CLASSES.LOADING_LOGO;
private emailError: string = '';
private passwordError: string = '';
public onLogoClick(): void {
location.reload();
}
public onLogoClick(): void {
location.reload();
}
public setEmail(value: string): void {
this.email = value;
this.emailError = '';
}
public setEmail(value: string): void {
this.email = value;
this.emailError = '';
}
public setPassword(value: string): void {
this.password = value;
this.passwordError = '';
}
public setPassword(value: string): void {
this.password = value;
this.passwordError = '';
}
public onSignUpClick(): void {
this.$router.push(ROUTES.REGISTER.path);
}
public onSignUpClick(): void {
this.$router.push(ROUTES.REGISTER.path);
}
public async onLogin(): Promise<void> {
let self = this;
this.$segment.track(EVENTS.CLICKED_LOGIN);
public async onLogin(): Promise<void> {
let self = this;
this.$segment.track(EVENTS.CLICKED_LOGIN);
if (!self.validateFields()) {
return;
}
if (!self.validateFields()) {
return;
}
let loginResponse = await getTokenRequest(this.email, this.password);
if (!loginResponse.isSuccess) {
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, loginResponse.errorMessage);
let loginResponse = await getTokenRequest(this.email, this.password);
if (!loginResponse.isSuccess) {
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, loginResponse.errorMessage);
return;
}
return;
}
this.activateLoadingOverlay();
this.activateLoadingOverlay();
setTimeout(() => {
setToken(loginResponse.data);
this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.LOADING);
this.$router.push(ROUTES.PROJECT_OVERVIEW.path + '/' + ROUTES.PROJECT_DETAILS.path);
}, 2000);
}
setTimeout(() => {
AuthToken.set(loginResponse.data);
this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.LOADING);
this.$router.push(ROUTES.PROJECT_OVERVIEW.path + '/' + ROUTES.PROJECT_DETAILS.path);
}, 2000);
}
private validateFields(): boolean {
let isNoErrors = true;
private validateFields(): boolean {
let isNoErrors = true;
if (!validateEmail(this.email.trim())) {
this.emailError = 'Invalid Email';
isNoErrors = false;
}
if (!validateEmail(this.email.trim())) {
this.emailError = 'Invalid Email';
isNoErrors = false;
}
if (!validatePassword(this.password)) {
this.passwordError = 'Invalid Password';
isNoErrors = false;
}
if (!validatePassword(this.password)) {
this.passwordError = 'Invalid Password';
isNoErrors = false;
}
return isNoErrors;
}
return isNoErrors;
}
private activateLoadingOverlay(): void {
this.loadingClassName = LOADING_CLASSES.LOADING_OVERLAY_ACTIVE;
this.loadingLogoClassName = LOADING_CLASSES.LOADING_LOGO_ACTIVE;
}
}
private activateLoadingOverlay(): void {
this.loadingClassName = LOADING_CLASSES.LOADING_OVERLAY_ACTIVE;
this.loadingLogoClassName = LOADING_CLASSES.LOADING_LOGO_ACTIVE;
}
}
</script>
<style src="./login.scss" scoped lang="scss"></style>