From 5beb89f223539f1e415a976ff104f772526b4d20 Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Mon, 9 Nov 2020 16:25:27 +0100 Subject: refactor scoped token service --- .../about-instance/about-instance.component.ts | 2 +- .../video-block-list/video-block-list.component.ts | 2 +- .../my-account-applications.component.html | 4 +- .../my-account-applications.component.ts | 59 +++++++++++++--------- client/src/app/+my-account/my-account.component.ts | 10 ++-- client/src/app/+my-account/my-account.module.ts | 4 +- .../video-user-subscriptions.component.ts | 22 ++++++-- client/src/app/core/auth/auth.service.ts | 45 ----------------- client/src/app/core/core.module.ts | 2 + client/src/app/core/index.ts | 1 + client/src/app/core/scoped-tokens/index.ts | 1 + .../core/scoped-tokens/scoped-tokens.service.ts | 33 ++++++++++++ client/src/app/helpers/utils.ts | 2 +- .../abuse-list-table.component.ts | 2 +- .../shared-forms/input-readonly-copy.component.ts | 1 - .../app/shared/shared-main/video/video.service.ts | 21 ++++---- client/src/environments/environment.e2e.ts | 2 +- client/src/environments/environment.hmr.ts | 2 +- client/src/environments/environment.prod.ts | 2 +- client/src/environments/environment.ts | 2 +- client/src/sass/include/_mixins.scss | 2 +- 21 files changed, 115 insertions(+), 106 deletions(-) create mode 100644 client/src/app/core/scoped-tokens/index.ts create mode 100644 client/src/app/core/scoped-tokens/scoped-tokens.service.ts (limited to 'client/src') diff --git a/client/src/app/+about/about-instance/about-instance.component.ts b/client/src/app/+about/about-instance/about-instance.component.ts index e74b5daeb..92ecd5263 100644 --- a/client/src/app/+about/about-instance/about-instance.component.ts +++ b/client/src/app/+about/about-instance/about-instance.component.ts @@ -3,7 +3,7 @@ import { AfterViewChecked, Component, OnInit, ViewChild } from '@angular/core' import { ActivatedRoute } from '@angular/router' import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' import { Notifier } from '@app/core' -import { copyToClipboard } from '../../../assets/player/utils' +import { copyToClipboard } from '../../../root-helpers/utils' import { InstanceService } from '@app/shared/shared-instance' import { ServerConfig } from '@shared/models' import { ResolverData } from './about-instance.resolver' diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts index 1d0e56bfd..aa6b5d0a9 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts @@ -161,7 +161,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV getVideoEmbed (entry: VideoBlacklist) { return buildVideoOrPlaylistEmbed( buildVideoLink({ - baseUrl: `${environment.embedUrl}/videos/embed/${entry.video.uuid}`, + baseUrl: `${environment.originServerUrl}/videos/embed/${entry.video.uuid}`, title: false, warningTitle: false }) diff --git a/client/src/app/+my-account/my-account-applications/my-account-applications.component.html b/client/src/app/+my-account/my-account-applications/my-account-applications.component.html index 62e2cb59b..53a9c91ac 100644 --- a/client/src/app/+my-account/my-account-applications/my-account-applications.component.html +++ b/client/src/app/+my-account/my-account-applications/my-account-applications.component.html @@ -7,8 +7,8 @@

SUBSCRIPTION FEED

- Used to retrieve the list of videos of the creators - you subscribed to from outside PeerTube + Use third-party feed aggregators to retrieve the list of videos from + channels you subscribed to. Make sure to keep your token private.
diff --git a/client/src/app/+my-account/my-account-applications/my-account-applications.component.ts b/client/src/app/+my-account/my-account-applications/my-account-applications.component.ts index c3f09dfe3..233e42c83 100644 --- a/client/src/app/+my-account/my-account-applications/my-account-applications.component.ts +++ b/client/src/app/+my-account/my-account-applications/my-account-applications.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit } from '@angular/core' -import { AuthService, Notifier, ConfirmService } from '@app/core' +import { AuthService, Notifier, ConfirmService, ScopedTokensService } from '@app/core' import { VideoService } from '@app/shared/shared-main' import { FeedFormat } from '@shared/models' -import { Subject, merge } from 'rxjs' -import { debounceTime } from 'rxjs/operators' +import { ScopedToken } from '@shared/models/users/user-scoped-token' +import { environment } from '../../../environments/environment' @Component({ selector: 'my-account-applications', @@ -15,11 +15,11 @@ export class MyAccountApplicationsComponent implements OnInit { feedUrl: string feedToken: string - private baseURL = window.location.protocol + '//' + window.location.host - private tokenStream = new Subject() + private baseURL = environment.originServerUrl constructor ( private authService: AuthService, + private scopedTokensService: ScopedTokensService, private videoService: VideoService, private notifier: Notifier, private confirmService: ConfirmService @@ -27,31 +27,40 @@ export class MyAccountApplicationsComponent implements OnInit { ngOnInit () { this.feedUrl = this.baseURL + this.scopedTokensService.getScopedTokens() + .subscribe( + tokens => this.regenApplications(tokens), - merge( - this.tokenStream, - this.authService.userInformationLoaded - ).pipe(debounceTime(400)) - .subscribe( - _ => { - const user = this.authService.getUser() - this.videoService.getVideoSubscriptionFeedUrls(user.account.id) - .then(feeds => this.feedUrl = this.baseURL + feeds.find(f => f.format === FeedFormat.RSS).url) - .then(_ => this.authService.getScopedTokens().then(tokens => this.feedToken = tokens.feedToken)) - }, - - err => { - this.notifier.error(err.message) - } - ) + err => { + this.notifier.error(err.message) + } + ) } async renewToken () { - const res = await this.confirmService.confirm('Renewing the token will disallow previously configured clients from retrieving the feed until they use the new token. Proceed?', 'Renew token') + const res = await this.confirmService.confirm( + $localize`Renewing the token will disallow previously configured clients from retrieving the feed until they use the new token. Proceed?`, + $localize`Renew token` + ) if (res === false) return - await this.authService.renewScopedTokens() - this.notifier.success('Token renewed. Update your client configuration accordingly.') - this.tokenStream.next() + this.scopedTokensService.renewScopedTokens().subscribe( + tokens => { + this.regenApplications(tokens) + this.notifier.success($localize`Token renewed. Update your client configuration accordingly.`) + }, + + err => { + this.notifier.error(err.message) + } + ) + + } + + private regenApplications (tokens: ScopedToken) { + const user = this.authService.getUser() + const feeds = this.videoService.getVideoSubscriptionFeedUrls(user.account.id, tokens.feedToken) + this.feedUrl = this.baseURL + feeds.find(f => f.format === FeedFormat.RSS).url + this.feedToken = tokens.feedToken } } diff --git a/client/src/app/+my-account/my-account.component.ts b/client/src/app/+my-account/my-account.component.ts index 12966aebb..eaf8a72e9 100644 --- a/client/src/app/+my-account/my-account.component.ts +++ b/client/src/app/+my-account/my-account.component.ts @@ -41,11 +41,6 @@ export class MyAccountComponent implements OnInit { label: $localize`Abuse reports`, routerLink: '/my-account/abuses', iconName: 'flag' - }, - { - label: $localize`Applications`, - routerLink: '/my-account/applications', - iconName: 'codesandbox' } ] } @@ -61,6 +56,11 @@ export class MyAccountComponent implements OnInit { routerLink: '/my-account/notifications' }, + { + label: $localize`Applications`, + routerLink: '/my-account/applications' + }, + moderationEntries ] } diff --git a/client/src/app/+my-account/my-account.module.ts b/client/src/app/+my-account/my-account.module.ts index 70bf58aae..076864563 100644 --- a/client/src/app/+my-account/my-account.module.ts +++ b/client/src/app/+my-account/my-account.module.ts @@ -20,8 +20,8 @@ import { MyAccountDangerZoneComponent } from './my-account-settings/my-account-d import { MyAccountNotificationPreferencesComponent } from './my-account-settings/my-account-notification-preferences' import { MyAccountProfileComponent } from './my-account-settings/my-account-profile/my-account-profile.component' import { MyAccountSettingsComponent } from './my-account-settings/my-account-settings.component' +import { MyAccountApplicationsComponent } from './my-account-applications/my-account-applications.component' import { MyAccountComponent } from './my-account.component' -import { VideoChangeOwnershipComponent } from './my-account-applications/my-account-applications.component' @NgModule({ imports: [ @@ -46,13 +46,13 @@ import { VideoChangeOwnershipComponent } from './my-account-applications/my-acco MyAccountChangePasswordComponent, MyAccountProfileComponent, MyAccountChangeEmailComponent, + MyAccountApplicationsComponent, MyAccountDangerZoneComponent, MyAccountBlocklistComponent, MyAccountAbusesListComponent, MyAccountServerBlocklistComponent, MyAccountNotificationsComponent, - MyAccountNotificationPreferencesComponent, MyAccountNotificationPreferencesComponent ], diff --git a/client/src/app/+videos/video-list/video-user-subscriptions.component.ts b/client/src/app/+videos/video-list/video-user-subscriptions.component.ts index 10031d6cc..03881c295 100644 --- a/client/src/app/+videos/video-list/video-user-subscriptions.component.ts +++ b/client/src/app/+videos/video-list/video-user-subscriptions.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' -import { AuthService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core' +import { AuthService, LocalStorageService, Notifier, ScopedTokensService, ScreenService, ServerService, UserService } from '@app/core' import { HooksService } from '@app/core/plugins/hooks.service' import { immutableAssign } from '@app/helpers' import { VideoService } from '@app/shared/shared-main' @@ -9,6 +9,7 @@ import { AbstractVideoList, OwnerDisplayType } from '@app/shared/shared-video-mi import { VideoSortField, FeedFormat } from '@shared/models' import { copyToClipboard } from '../../../root-helpers/utils' import { environment } from '../../../environments/environment' +import { forkJoin } from 'rxjs' @Component({ selector: 'my-videos-user-subscriptions', @@ -32,7 +33,8 @@ export class VideoUserSubscriptionsComponent extends AbstractVideoList implement protected storageService: LocalStorageService, private userSubscription: UserSubscriptionService, private hooks: HooksService, - private videoService: VideoService + private videoService: VideoService, + private scopedTokensService: ScopedTokensService ) { super() @@ -49,9 +51,19 @@ export class VideoUserSubscriptionsComponent extends AbstractVideoList implement super.ngOnInit() const user = this.authService.getUser() - let feedUrl = environment.embedUrl - this.videoService.getVideoSubscriptionFeedUrls(user.account.id) - .then((feeds: any) => feedUrl = feedUrl + feeds.find((f: any) => f.format === FeedFormat.RSS).url) + let feedUrl = environment.originServerUrl + + this.scopedTokensService.getScopedTokens().subscribe( + tokens => { + const feeds = this.videoService.getVideoSubscriptionFeedUrls(user.account.id, tokens.feedToken) + feedUrl = feedUrl + feeds.find((f: any) => f.format === FeedFormat.RSS).url + }, + + err => { + this.notifier.error(err.message) + } + ) + this.actions.unshift({ label: $localize`Feed`, iconName: 'syndication', diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts index 224f35f82..fd6062d3f 100644 --- a/client/src/app/core/auth/auth.service.ts +++ b/client/src/app/core/auth/auth.service.ts @@ -11,7 +11,6 @@ import { environment } from '../../../environments/environment' import { RestExtractor } from '../rest/rest-extractor.service' import { AuthStatus } from './auth-status.model' import { AuthUser } from './auth-user.model' -import { ScopedTokenType, ScopedToken } from '@shared/models/users/user-scoped-token' interface UserLoginWithUsername extends UserLogin { access_token: string @@ -27,7 +26,6 @@ export class AuthService { private static BASE_CLIENT_URL = environment.apiUrl + '/api/v1/oauth-clients/local' private static BASE_TOKEN_URL = environment.apiUrl + '/api/v1/users/token' private static BASE_REVOKE_TOKEN_URL = environment.apiUrl + '/api/v1/users/revoke-token' - private static BASE_SCOPED_TOKENS_URL = environment.apiUrl + '/api/v1/users/scoped-tokens' private static BASE_USER_INFORMATION_URL = environment.apiUrl + '/api/v1/users/me' private static LOCAL_STORAGE_OAUTH_CLIENT_KEYS = { CLIENT_ID: 'client_id', @@ -43,7 +41,6 @@ export class AuthService { private loginChanged: Subject private user: AuthUser = null private refreshingTokenObservable: Observable - private scopedTokens: ScopedToken constructor ( private http: HttpClient, @@ -247,48 +244,6 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular ) } - getScopedTokens (): Promise { - return new Promise((res, rej) => { - if (this.scopedTokens) return res(this.scopedTokens) - - const authHeaderValue = this.getRequestHeaderValue() - const headers = new HttpHeaders().set('Authorization', authHeaderValue) - - this.http.get(AuthService.BASE_SCOPED_TOKENS_URL, { headers }) - .subscribe( - scopedTokens => { - this.scopedTokens = scopedTokens - res(this.scopedTokens) - }, - - err => { - console.error(err) - rej(err) - } - ) - }) - } - - renewScopedTokens (): Promise { - return new Promise((res, rej) => { - const authHeaderValue = this.getRequestHeaderValue() - const headers = new HttpHeaders().set('Authorization', authHeaderValue) - - this.http.post(AuthService.BASE_SCOPED_TOKENS_URL, {}, { headers }) - .subscribe( - scopedTokens => { - this.scopedTokens = scopedTokens - res(this.scopedTokens) - }, - - err => { - console.error(err) - rej(err) - } - ) - }) - } - private mergeUserInformation (obj: UserLoginWithUsername): Observable { // User is not loaded yet, set manually auth header const headers = new HttpHeaders().set('Authorization', `${obj.token_type} ${obj.access_token}`) diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index 6c0a2245d..f51f1920d 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts @@ -12,6 +12,7 @@ import { LoadingBarModule } from '@ngx-loading-bar/core' import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client' import { LoadingBarRouterModule } from '@ngx-loading-bar/router' import { AuthService } from './auth' +import { ScopedTokensService } from './scoped-tokens' import { ConfirmService } from './confirm' import { CheatSheetComponent } from './hotkeys' import { MenuService } from './menu' @@ -57,6 +58,7 @@ import { LocalStorageService, ScreenService, SessionStorageService } from './wra providers: [ AuthService, + ScopedTokensService, ConfirmService, ServerService, ThemeService, diff --git a/client/src/app/core/index.ts b/client/src/app/core/index.ts index a0c34543d..9245ff6fc 100644 --- a/client/src/app/core/index.ts +++ b/client/src/app/core/index.ts @@ -1,4 +1,5 @@ export * from './auth' +export * from './scoped-tokens' export * from './confirm' export * from './hotkeys' export * from './menu' diff --git a/client/src/app/core/scoped-tokens/index.ts b/client/src/app/core/scoped-tokens/index.ts new file mode 100644 index 000000000..c9a48ffcd --- /dev/null +++ b/client/src/app/core/scoped-tokens/index.ts @@ -0,0 +1 @@ +export * from './scoped-tokens.service' diff --git a/client/src/app/core/scoped-tokens/scoped-tokens.service.ts b/client/src/app/core/scoped-tokens/scoped-tokens.service.ts new file mode 100644 index 000000000..8e3697c31 --- /dev/null +++ b/client/src/app/core/scoped-tokens/scoped-tokens.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@angular/core' +import { HttpClient } from '@angular/common/http' +import { environment } from '../../../environments/environment' +import { AuthService } from '../auth' +import { ScopedToken } from '@shared/models/users/user-scoped-token' +import { catchError } from 'rxjs/operators' +import { RestExtractor } from '../rest' + +@Injectable() +export class ScopedTokensService { + private static BASE_SCOPED_TOKENS_URL = environment.apiUrl + '/api/v1/users/scoped-tokens' + + constructor ( + private authHttp: HttpClient, + private restExtractor: RestExtractor + ) {} + + getScopedTokens () { + return this.authHttp + .get(ScopedTokensService.BASE_SCOPED_TOKENS_URL) + .pipe( + catchError(res => this.restExtractor.handleError(res)) + ) + } + + renewScopedTokens () { + return this.authHttp + .post(ScopedTokensService.BASE_SCOPED_TOKENS_URL, {}) + .pipe( + catchError(res => this.restExtractor.handleError(res)) + ) + } +} diff --git a/client/src/app/helpers/utils.ts b/client/src/app/helpers/utils.ts index a22507f46..9c805b4ca 100644 --- a/client/src/app/helpers/utils.ts +++ b/client/src/app/helpers/utils.ts @@ -58,7 +58,7 @@ function getAbsoluteAPIUrl () { } function getAbsoluteEmbedUrl () { - let absoluteEmbedUrl = environment.embedUrl + let absoluteEmbedUrl = environment.originServerUrl if (!absoluteEmbedUrl) { // The Embed is on the same domain absoluteEmbedUrl = window.location.origin diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts index ca0d23699..807665b9c 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts +++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts @@ -112,7 +112,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV getVideoEmbed (abuse: AdminAbuse) { return buildVideoOrPlaylistEmbed( buildVideoLink({ - baseUrl: `${environment.embedUrl}/videos/embed/${abuse.video.uuid}`, + baseUrl: `${environment.originServerUrl}/videos/embed/${abuse.video.uuid}`, title: false, warningTitle: false, startTime: abuse.video.startAt, diff --git a/client/src/app/shared/shared-forms/input-readonly-copy.component.ts b/client/src/app/shared/shared-forms/input-readonly-copy.component.ts index 520827a53..b04d69d05 100644 --- a/client/src/app/shared/shared-forms/input-readonly-copy.component.ts +++ b/client/src/app/shared/shared-forms/input-readonly-copy.component.ts @@ -1,6 +1,5 @@ import { Component, Input } from '@angular/core' import { Notifier } from '@app/core' -import { FormGroup } from '@angular/forms' @Component({ selector: 'my-input-readonly-copy', diff --git a/client/src/app/shared/shared-main/video/video.service.ts b/client/src/app/shared/shared-main/video/video.service.ts index b81540e8d..70be5d7d2 100644 --- a/client/src/app/shared/shared-main/video/video.service.ts +++ b/client/src/app/shared/shared-main/video/video.service.ts @@ -18,8 +18,7 @@ import { VideoFilter, VideoPrivacy, VideoSortField, - VideoUpdate, - VideoCreate + VideoUpdate } from '@shared/models' import { environment } from '../../../../environments/environment' import { Account } from '../account/account.model' @@ -44,13 +43,13 @@ export interface VideosProvider { export class VideoService implements VideosProvider { static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/' static BASE_FEEDS_URL = environment.apiUrl + '/feeds/videos.' + static BASE_SUBSCRIPTION_FEEDS_URL = environment.apiUrl + '/feeds/subscriptions.' constructor ( private authHttp: HttpClient, private restExtractor: RestExtractor, private restService: RestService, - private serverService: ServerService, - private authService: AuthService + private serverService: ServerService ) {} getVideoViewUrl (uuid: string) { @@ -238,22 +237,22 @@ export class VideoService implements VideosProvider { ) } - buildBaseFeedUrls (params: HttpParams) { + buildBaseFeedUrls (params: HttpParams, base = VideoService.BASE_FEEDS_URL) { const feeds = [ { format: FeedFormat.RSS, label: 'media rss 2.0', - url: VideoService.BASE_FEEDS_URL + FeedFormat.RSS.toLowerCase() + url: base + FeedFormat.RSS.toLowerCase() }, { format: FeedFormat.ATOM, label: 'atom 1.0', - url: VideoService.BASE_FEEDS_URL + FeedFormat.ATOM.toLowerCase() + url: base + FeedFormat.ATOM.toLowerCase() }, { format: FeedFormat.JSON, label: 'json 1.0', - url: VideoService.BASE_FEEDS_URL + FeedFormat.JSON.toLowerCase() + url: base + FeedFormat.JSON.toLowerCase() } ] @@ -294,14 +293,12 @@ export class VideoService implements VideosProvider { return this.buildBaseFeedUrls(params) } - async getVideoSubscriptionFeedUrls (accountId: number) { + getVideoSubscriptionFeedUrls (accountId: number, feedToken: string) { let params = this.restService.addRestGetParams(new HttpParams()) params = params.set('accountId', accountId.toString()) - - const { feedToken } = await this.authService.getScopedTokens() params = params.set('token', feedToken) - return this.buildBaseFeedUrls(params) + return this.buildBaseFeedUrls(params, VideoService.BASE_SUBSCRIPTION_FEEDS_URL) } getVideoFileMetadata (metadataUrl: string) { diff --git a/client/src/environments/environment.e2e.ts b/client/src/environments/environment.e2e.ts index b33ff9f86..a1a58e36f 100644 --- a/client/src/environments/environment.e2e.ts +++ b/client/src/environments/environment.e2e.ts @@ -2,5 +2,5 @@ export const environment = { production: false, hmr: false, apiUrl: 'http://localhost:9001', - embedUrl: 'http://localhost:9001' + originServerUrl: 'http://localhost:9001' } diff --git a/client/src/environments/environment.hmr.ts b/client/src/environments/environment.hmr.ts index 3b6eff302..ab7631920 100644 --- a/client/src/environments/environment.hmr.ts +++ b/client/src/environments/environment.hmr.ts @@ -2,5 +2,5 @@ export const environment = { production: false, hmr: true, apiUrl: '', - embedUrl: 'http://localhost:9000' + originServerUrl: 'http://localhost:9000' } diff --git a/client/src/environments/environment.prod.ts b/client/src/environments/environment.prod.ts index 2e9b9fefe..e1b736c61 100644 --- a/client/src/environments/environment.prod.ts +++ b/client/src/environments/environment.prod.ts @@ -2,5 +2,5 @@ export const environment = { production: true, hmr: false, apiUrl: '', - embedUrl: '' + originServerUrl: '' } diff --git a/client/src/environments/environment.ts b/client/src/environments/environment.ts index e00523976..5d7011265 100644 --- a/client/src/environments/environment.ts +++ b/client/src/environments/environment.ts @@ -12,5 +12,5 @@ export const environment = { production: true, hmr: false, apiUrl: '', - embedUrl: '' + originServerUrl: '' } diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss index 4d70110fe..e6491b492 100644 --- a/client/src/sass/include/_mixins.scss +++ b/client/src/sass/include/_mixins.scss @@ -225,7 +225,7 @@ line-height: $button-height; border-radius: 3px; text-align: center; - padding: 0 13px 0 13px; + padding: 0 17px 0 13px; cursor: pointer; } -- cgit v1.2.3