From 0bd78bf30b2ae159791bdc90d17ed18e0327f621 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 23 Mar 2018 14:26:20 +0100 Subject: [PATCH] Proxify local storage and handle if it is unavailable --- .../jobs/jobs-list/jobs-list.component.ts | 8 +-- client/src/app/core/auth/auth-user.model.ts | 59 ++++++++-------- client/src/app/core/server/server.service.ts | 5 +- .../app/shared/misc/peertube-local-storage.ts | 70 +++++++++++++++++++ client/src/app/shared/rest/rest-table.ts | 5 +- .../+video-watch/video-watch.component.ts | 8 ++- 6 files changed, 116 insertions(+), 39 deletions(-) create mode 100644 client/src/app/shared/misc/peertube-local-storage.ts diff --git a/client/src/app/+admin/jobs/jobs-list/jobs-list.component.ts b/client/src/app/+admin/jobs/jobs-list/jobs-list.component.ts index e3f317e6d..ad2f05c6b 100644 --- a/client/src/app/+admin/jobs/jobs-list/jobs-list.component.ts +++ b/client/src/app/+admin/jobs/jobs-list/jobs-list.component.ts @@ -1,12 +1,12 @@ import { Component, OnInit } from '@angular/core' +import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' import { NotificationsService } from 'angular2-notifications' import { SortMeta } from 'primeng/primeng' import { Job } from '../../../../../../shared/index' import { JobState } from '../../../../../../shared/models' import { RestPagination, RestTable } from '../../../shared' -import { viewportHeight } from '../../../shared/misc/utils' -import { JobService } from '../shared' import { RestExtractor } from '../../../shared/rest/rest-extractor.service' +import { JobService } from '../shared' @Component({ selector: 'my-jobs-list', @@ -56,12 +56,12 @@ export class JobsListComponent extends RestTable implements OnInit { } private loadJobState () { - const result = localStorage.getItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE) + const result = peertubeLocalStorage.getItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE) if (result) this.jobState = result as JobState } private saveJobState () { - localStorage.setItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE, this.jobState) + peertubeLocalStorage.setItem(JobsListComponent.JOB_STATE_LOCAL_STORAGE_STATE, this.jobState) } } diff --git a/client/src/app/core/auth/auth-user.model.ts b/client/src/app/core/auth/auth-user.model.ts index 9ad275392..366eea110 100644 --- a/client/src/app/core/auth/auth-user.model.ts +++ b/client/src/app/core/auth/auth-user.model.ts @@ -1,7 +1,8 @@ +import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' +import { UserRight } from '../../../../../shared/models/users/user-right.enum' // Do not use the barrel (dependency loop) import { hasUserRight, UserRole } from '../../../../../shared/models/users/user-role' import { User, UserConstructorHash } from '../../shared/users/user.model' -import { UserRight } from '../../../../../shared/models/users/user-right.enum' export type TokenOptions = { accessToken: string @@ -22,9 +23,9 @@ class Tokens { tokenType: string static load () { - const accessTokenLocalStorage = localStorage.getItem(this.KEYS.ACCESS_TOKEN) - const refreshTokenLocalStorage = localStorage.getItem(this.KEYS.REFRESH_TOKEN) - const tokenTypeLocalStorage = localStorage.getItem(this.KEYS.TOKEN_TYPE) + const accessTokenLocalStorage = peertubeLocalStorage.getItem(this.KEYS.ACCESS_TOKEN) + const refreshTokenLocalStorage = peertubeLocalStorage.getItem(this.KEYS.REFRESH_TOKEN) + const tokenTypeLocalStorage = peertubeLocalStorage.getItem(this.KEYS.TOKEN_TYPE) if (accessTokenLocalStorage && refreshTokenLocalStorage && tokenTypeLocalStorage) { return new Tokens({ @@ -38,9 +39,9 @@ class Tokens { } static flush () { - localStorage.removeItem(this.KEYS.ACCESS_TOKEN) - localStorage.removeItem(this.KEYS.REFRESH_TOKEN) - localStorage.removeItem(this.KEYS.TOKEN_TYPE) + peertubeLocalStorage.removeItem(this.KEYS.ACCESS_TOKEN) + peertubeLocalStorage.removeItem(this.KEYS.REFRESH_TOKEN) + peertubeLocalStorage.removeItem(this.KEYS.TOKEN_TYPE) } constructor (hash?: TokenOptions) { @@ -57,9 +58,9 @@ class Tokens { } save () { - localStorage.setItem(Tokens.KEYS.ACCESS_TOKEN, this.accessToken) - localStorage.setItem(Tokens.KEYS.REFRESH_TOKEN, this.refreshToken) - localStorage.setItem(Tokens.KEYS.TOKEN_TYPE, this.tokenType) + peertubeLocalStorage.setItem(Tokens.KEYS.ACCESS_TOKEN, this.accessToken) + peertubeLocalStorage.setItem(Tokens.KEYS.REFRESH_TOKEN, this.refreshToken) + peertubeLocalStorage.setItem(Tokens.KEYS.TOKEN_TYPE, this.tokenType) } } @@ -76,16 +77,16 @@ export class AuthUser extends User { tokens: Tokens static load () { - const usernameLocalStorage = localStorage.getItem(this.KEYS.USERNAME) + const usernameLocalStorage = peertubeLocalStorage.getItem(this.KEYS.USERNAME) if (usernameLocalStorage) { return new AuthUser( { - id: parseInt(localStorage.getItem(this.KEYS.ID), 10), - username: localStorage.getItem(this.KEYS.USERNAME), - email: localStorage.getItem(this.KEYS.EMAIL), - role: parseInt(localStorage.getItem(this.KEYS.ROLE), 10) as UserRole, - displayNSFW: localStorage.getItem(this.KEYS.DISPLAY_NSFW) === 'true', - autoPlayVideo: localStorage.getItem(this.KEYS.AUTO_PLAY_VIDEO) === 'true' + id: parseInt(peertubeLocalStorage.getItem(this.KEYS.ID), 10), + username: peertubeLocalStorage.getItem(this.KEYS.USERNAME), + email: peertubeLocalStorage.getItem(this.KEYS.EMAIL), + role: parseInt(peertubeLocalStorage.getItem(this.KEYS.ROLE), 10) as UserRole, + displayNSFW: peertubeLocalStorage.getItem(this.KEYS.DISPLAY_NSFW) === 'true', + autoPlayVideo: peertubeLocalStorage.getItem(this.KEYS.AUTO_PLAY_VIDEO) === 'true' }, Tokens.load() ) @@ -95,12 +96,12 @@ export class AuthUser extends User { } static flush () { - localStorage.removeItem(this.KEYS.USERNAME) - localStorage.removeItem(this.KEYS.ID) - localStorage.removeItem(this.KEYS.ROLE) - localStorage.removeItem(this.KEYS.DISPLAY_NSFW) - localStorage.removeItem(this.KEYS.AUTO_PLAY_VIDEO) - localStorage.removeItem(this.KEYS.EMAIL) + peertubeLocalStorage.removeItem(this.KEYS.USERNAME) + peertubeLocalStorage.removeItem(this.KEYS.ID) + peertubeLocalStorage.removeItem(this.KEYS.ROLE) + peertubeLocalStorage.removeItem(this.KEYS.DISPLAY_NSFW) + peertubeLocalStorage.removeItem(this.KEYS.AUTO_PLAY_VIDEO) + peertubeLocalStorage.removeItem(this.KEYS.EMAIL) Tokens.flush() } @@ -131,12 +132,12 @@ export class AuthUser extends User { } save () { - localStorage.setItem(AuthUser.KEYS.ID, this.id.toString()) - localStorage.setItem(AuthUser.KEYS.USERNAME, this.username) - localStorage.setItem(AuthUser.KEYS.EMAIL, this.email) - localStorage.setItem(AuthUser.KEYS.ROLE, this.role.toString()) - localStorage.setItem(AuthUser.KEYS.DISPLAY_NSFW, JSON.stringify(this.displayNSFW)) - localStorage.setItem(AuthUser.KEYS.AUTO_PLAY_VIDEO, JSON.stringify(this.autoPlayVideo)) + peertubeLocalStorage.setItem(AuthUser.KEYS.ID, this.id.toString()) + peertubeLocalStorage.setItem(AuthUser.KEYS.USERNAME, this.username) + peertubeLocalStorage.setItem(AuthUser.KEYS.EMAIL, this.email) + peertubeLocalStorage.setItem(AuthUser.KEYS.ROLE, this.role.toString()) + peertubeLocalStorage.setItem(AuthUser.KEYS.DISPLAY_NSFW, JSON.stringify(this.displayNSFW)) + peertubeLocalStorage.setItem(AuthUser.KEYS.AUTO_PLAY_VIDEO, JSON.stringify(this.autoPlayVideo)) this.tokens.save() } } diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index 0b63ef5be..206ec7bcd 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts @@ -1,5 +1,6 @@ import { HttpClient } from '@angular/common/http' import { Injectable } from '@angular/core' +import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' import 'rxjs/add/operator/do' import { ReplaySubject } from 'rxjs/ReplaySubject' import { ServerConfig } from '../../../../../shared' @@ -140,11 +141,11 @@ export class ServerService { } private saveConfigLocally (config: ServerConfig) { - localStorage.setItem(ServerService.CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config)) + peertubeLocalStorage.setItem(ServerService.CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config)) } private loadConfigLocally () { - const configString = localStorage.getItem(ServerService.CONFIG_LOCAL_STORAGE_KEY) + const configString = peertubeLocalStorage.getItem(ServerService.CONFIG_LOCAL_STORAGE_KEY) if (configString) { try { diff --git a/client/src/app/shared/misc/peertube-local-storage.ts b/client/src/app/shared/misc/peertube-local-storage.ts new file mode 100644 index 000000000..ad761c82f --- /dev/null +++ b/client/src/app/shared/misc/peertube-local-storage.ts @@ -0,0 +1,70 @@ +// Thanks: https://github.com/capaj/localstorage-polyfill + +const valuesMap = new Map() + +class MemoryStorage { + [key: string]: any + [index: number]: string + + getItem (key) { + const stringKey = String(key) + if (valuesMap.has(key)) { + return String(valuesMap.get(stringKey)) + } + + return null + } + + setItem (key, val) { + valuesMap.set(String(key), String(val)) + } + + removeItem (key) { + valuesMap.delete(key) + } + + clear () { + valuesMap.clear() + } + + key (i: any) { + if (arguments.length === 0) { + throw new TypeError('Failed to execute "key" on "Storage": 1 argument required, but only 0 present.') + } + + const arr = Array.from(valuesMap.keys()) + return arr[i] + } + + get length () { + return valuesMap.size + } +} + +let peertubeLocalStorage: Storage +try { + peertubeLocalStorage = localStorage +} catch (err) { + const instance = new MemoryStorage() + + peertubeLocalStorage = new Proxy(instance, { + set: function (obj, prop, value) { + if (MemoryStorage.prototype.hasOwnProperty(prop)) { + instance[prop] = value + } else { + instance.setItem(prop, value) + } + return true + }, + get: function (target, name) { + if (MemoryStorage.prototype.hasOwnProperty(name)) { + return instance[name] + } + if (valuesMap.has(name)) { + return instance.getItem(name) + } + } + }) +} + +export { peertubeLocalStorage } diff --git a/client/src/app/shared/rest/rest-table.ts b/client/src/app/shared/rest/rest-table.ts index 165fc4e45..fe1a91d2d 100644 --- a/client/src/app/shared/rest/rest-table.ts +++ b/client/src/app/shared/rest/rest-table.ts @@ -1,3 +1,4 @@ +import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' import { LazyLoadEvent } from 'primeng/components/common/lazyloadevent' import { SortMeta } from 'primeng/components/common/sortmeta' @@ -15,7 +16,7 @@ export abstract class RestTable { protected abstract loadData (): void loadSort () { - const result = localStorage.getItem(this.sortLocalStorageKey) + const result = peertubeLocalStorage.getItem(this.sortLocalStorageKey) if (result) { try { @@ -42,7 +43,7 @@ export abstract class RestTable { } saveSort () { - localStorage.setItem(this.sortLocalStorageKey, JSON.stringify(this.sort)) + peertubeLocalStorage.setItem(this.sortLocalStorageKey, JSON.stringify(this.sort)) } } diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts index b60e58fb0..fda69efab 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts @@ -1,6 +1,7 @@ import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' import { RedirectService } from '@app/core/routing/redirect.service' +import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' import { MetaService } from '@ngx-meta/core' import { NotificationsService } from 'angular2-notifications' @@ -75,7 +76,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy { } ngOnInit () { - if (WebTorrent.WEBRTC_SUPPORT === false || localStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true') { + if ( + WebTorrent.WEBRTC_SUPPORT === false || + peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true' + ) { this.hasAlreadyAcceptedPrivacyConcern = true } @@ -262,7 +266,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { } acceptedPrivacyConcern () { - localStorage.setItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY, 'true') + peertubeLocalStorage.setItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY, 'true') this.hasAlreadyAcceptedPrivacyConcern = true } -- 2.25.1