mirror of https://github.com/Chocobozzz/PeerTube
Add debug component to help admins to fix IP issues
parent
2b3f1919fd
commit
5d79474cc6
|
@ -16,7 +16,7 @@
|
||||||
Configuration
|
Configuration
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a i18n *ngIf="hasJobsRight() || hasLogsRight()" routerLink="/admin/system" routerLinkActive="active" class="title-page">
|
<a i18n *ngIf="hasJobsRight() || hasLogsRight() || hasDebugRight()" routerLink="/admin/system" routerLinkActive="active" class="title-page">
|
||||||
System
|
System
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,15 +24,19 @@ export class AdminComponent {
|
||||||
return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
|
return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
|
||||||
}
|
}
|
||||||
|
|
||||||
hasJobsRight () {
|
hasConfigRight () {
|
||||||
return this.auth.getUser().hasRight(UserRight.MANAGE_JOBS)
|
return this.auth.getUser().hasRight(UserRight.MANAGE_CONFIGURATION)
|
||||||
}
|
}
|
||||||
|
|
||||||
hasLogsRight () {
|
hasLogsRight () {
|
||||||
return this.auth.getUser().hasRight(UserRight.MANAGE_LOGS)
|
return this.auth.getUser().hasRight(UserRight.MANAGE_LOGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
hasConfigRight () {
|
hasJobsRight () {
|
||||||
return this.auth.getUser().hasRight(UserRight.MANAGE_CONFIGURATION)
|
return this.auth.getUser().hasRight(UserRight.MANAGE_JOBS)
|
||||||
|
}
|
||||||
|
|
||||||
|
hasDebugRight () {
|
||||||
|
return this.auth.getUser().hasRight(UserRight.MANAGE_DEBUG)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service
|
||||||
import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist'
|
import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist'
|
||||||
import { JobsComponent } from '@app/+admin/system/jobs/jobs.component'
|
import { JobsComponent } from '@app/+admin/system/jobs/jobs.component'
|
||||||
import { JobService, LogsComponent, LogsService, SystemComponent } from '@app/+admin/system'
|
import { JobService, LogsComponent, LogsService, SystemComponent } from '@app/+admin/system'
|
||||||
|
import { DebugComponent, DebugService } from '@app/+admin/system/debug'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -54,6 +55,7 @@ import { JobService, LogsComponent, LogsService, SystemComponent } from '@app/+a
|
||||||
SystemComponent,
|
SystemComponent,
|
||||||
JobsComponent,
|
JobsComponent,
|
||||||
LogsComponent,
|
LogsComponent,
|
||||||
|
DebugComponent,
|
||||||
|
|
||||||
ConfigComponent,
|
ConfigComponent,
|
||||||
EditCustomConfigComponent
|
EditCustomConfigComponent
|
||||||
|
@ -68,6 +70,7 @@ import { JobService, LogsComponent, LogsService, SystemComponent } from '@app/+a
|
||||||
RedundancyService,
|
RedundancyService,
|
||||||
JobService,
|
JobService,
|
||||||
LogsService,
|
LogsService,
|
||||||
|
DebugService,
|
||||||
ConfigService
|
ConfigService
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<div class="root">
|
||||||
|
<h4>IP</h4>
|
||||||
|
|
||||||
|
<p>PeerTube thinks your public IP is <strong>{{ debug?.ip }}</strong>.</p>
|
||||||
|
|
||||||
|
<p>If this is not your correct public IP, please consider fixing it because:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Views may not be counted correctly (reduced compared to what they should be)</li>
|
||||||
|
<li>Anti brute force system could be overzealous</li>
|
||||||
|
<li>P2P system could not work correctly</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>To fix it:<p>
|
||||||
|
<ul>
|
||||||
|
<li>Check the <code>trust_proxy</code> configuration key</li>
|
||||||
|
<li>If you run PeerTube using Docker, check you run the <code>reverse-proxy</code> with <code>network_mode: "host"</code>
|
||||||
|
(see <a href="https://github.com/Chocobozzz/PeerTube/issues/1643#issuecomment-464789666">issue 1643</a>)</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
|
@ -0,0 +1,6 @@
|
||||||
|
@import '_variables';
|
||||||
|
@import '_mixins';
|
||||||
|
|
||||||
|
.root {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { Component, OnInit } from '@angular/core'
|
||||||
|
import { Notifier } from '@app/core'
|
||||||
|
import { Debug } from '@shared/models/server'
|
||||||
|
import { DebugService } from '@app/+admin/system/debug/debug.service'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: './debug.component.html',
|
||||||
|
styleUrls: [ './debug.component.scss' ]
|
||||||
|
})
|
||||||
|
export class DebugComponent implements OnInit {
|
||||||
|
debug: Debug
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private debugService: DebugService,
|
||||||
|
private notifier: Notifier
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit (): void {
|
||||||
|
this.load()
|
||||||
|
}
|
||||||
|
|
||||||
|
load () {
|
||||||
|
this.debugService.getDebug()
|
||||||
|
.subscribe(
|
||||||
|
debug => this.debug = debug,
|
||||||
|
|
||||||
|
err => this.notifier.error(err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { catchError } from 'rxjs/operators'
|
||||||
|
import { HttpClient } from '@angular/common/http'
|
||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { Observable } from 'rxjs'
|
||||||
|
import { environment } from '../../../../environments/environment'
|
||||||
|
import { RestExtractor, RestService } from '../../../shared'
|
||||||
|
import { Debug } from '@shared/models/server'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DebugService {
|
||||||
|
private static BASE_DEBUG_URL = environment.apiUrl + '/api/v1/server/debug'
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private authHttp: HttpClient,
|
||||||
|
private restService: RestService,
|
||||||
|
private restExtractor: RestExtractor
|
||||||
|
) {}
|
||||||
|
|
||||||
|
getDebug (): Observable<Debug> {
|
||||||
|
return this.authHttp.get<Debug>(DebugService.BASE_DEBUG_URL)
|
||||||
|
.pipe(
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './debug.component'
|
||||||
|
export * from './debug.service'
|
|
@ -9,7 +9,7 @@ import { LogLevel } from '@shared/models/server/log-level.type'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LogsService {
|
export class LogsService {
|
||||||
private static BASE_JOB_URL = environment.apiUrl + '/api/v1/server/logs'
|
private static BASE_LOG_URL = environment.apiUrl + '/api/v1/server/logs'
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private authHttp: HttpClient,
|
private authHttp: HttpClient,
|
||||||
|
@ -17,14 +17,14 @@ export class LogsService {
|
||||||
private restExtractor: RestExtractor
|
private restExtractor: RestExtractor
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getLogs (level: LogLevel, startDate: string, endDate?: string): Observable<any> {
|
getLogs (level: LogLevel, startDate: string, endDate?: string): Observable<any[]> {
|
||||||
let params = new HttpParams()
|
let params = new HttpParams()
|
||||||
params = params.append('startDate', startDate)
|
params = params.append('startDate', startDate)
|
||||||
params = params.append('level', level)
|
params = params.append('level', level)
|
||||||
|
|
||||||
if (endDate) params.append('endDate', endDate)
|
if (endDate) params.append('endDate', endDate)
|
||||||
|
|
||||||
return this.authHttp.get<any[]>(LogsService.BASE_JOB_URL, { params })
|
return this.authHttp.get<any[]>(LogsService.BASE_LOG_URL, { params })
|
||||||
.pipe(
|
.pipe(
|
||||||
map(rows => rows.map(r => new LogRow(r))),
|
map(rows => rows.map(r => new LogRow(r))),
|
||||||
catchError(err => this.restExtractor.handleError(err))
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
<div i18n class="form-sub-title">System</div>
|
<div i18n class="form-sub-title">System</div>
|
||||||
|
|
||||||
<div class="admin-sub-nav">
|
<div class="admin-sub-nav">
|
||||||
<a i18n routerLink="jobs" routerLinkActive="active">Jobs</a>
|
<a *ngIf="hasJobsRight()" i18n routerLink="jobs" routerLinkActive="active">Jobs</a>
|
||||||
|
|
||||||
<a i18n routerLink="logs" routerLinkActive="active">Logs</a>
|
<a *ngIf="hasLogsRight()" i18n routerLink="logs" routerLinkActive="active">Logs</a>
|
||||||
|
|
||||||
|
<a *ngIf="hasDebugRight()" i18n routerLink="debug" routerLinkActive="active">Debug</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,24 @@
|
||||||
import { Component } from '@angular/core'
|
import { Component } from '@angular/core'
|
||||||
|
import { UserRight } from '@shared/models'
|
||||||
|
import { AuthService } from '@app/core'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './system.component.html',
|
templateUrl: './system.component.html',
|
||||||
styleUrls: [ './system.component.scss' ]
|
styleUrls: [ './system.component.scss' ]
|
||||||
})
|
})
|
||||||
export class SystemComponent {
|
export class SystemComponent {
|
||||||
|
|
||||||
|
constructor (private auth: AuthService) {}
|
||||||
|
|
||||||
|
hasLogsRight () {
|
||||||
|
return this.auth.getUser().hasRight(UserRight.MANAGE_LOGS)
|
||||||
|
}
|
||||||
|
|
||||||
|
hasJobsRight () {
|
||||||
|
return this.auth.getUser().hasRight(UserRight.MANAGE_JOBS)
|
||||||
|
}
|
||||||
|
|
||||||
|
hasDebugRight () {
|
||||||
|
return this.auth.getUser().hasRight(UserRight.MANAGE_DEBUG)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { UserRight } from '../../../../../shared'
|
||||||
import { JobsComponent } from '@app/+admin/system/jobs/jobs.component'
|
import { JobsComponent } from '@app/+admin/system/jobs/jobs.component'
|
||||||
import { LogsComponent } from '@app/+admin/system/logs'
|
import { LogsComponent } from '@app/+admin/system/logs'
|
||||||
import { SystemComponent } from '@app/+admin/system/system.component'
|
import { SystemComponent } from '@app/+admin/system/system.component'
|
||||||
|
import { DebugComponent } from '@app/+admin/system/debug'
|
||||||
|
|
||||||
export const SystemRoutes: Routes = [
|
export const SystemRoutes: Routes = [
|
||||||
{
|
{
|
||||||
|
@ -38,6 +39,17 @@ export const SystemRoutes: Routes = [
|
||||||
title: 'Logs'
|
title: 'Logs'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'debug',
|
||||||
|
canActivate: [ UserRightGuard ],
|
||||||
|
component: DebugComponent,
|
||||||
|
data: {
|
||||||
|
meta: {
|
||||||
|
userRight: UserRight.MANAGE_DEBUG,
|
||||||
|
title: 'Debug'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import * as express from 'express'
|
||||||
|
import { UserRight } from '../../../../shared/models/users'
|
||||||
|
import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares'
|
||||||
|
|
||||||
|
const debugRouter = express.Router()
|
||||||
|
|
||||||
|
debugRouter.get('/debug',
|
||||||
|
authenticate,
|
||||||
|
ensureUserHasRight(UserRight.MANAGE_DEBUG),
|
||||||
|
asyncMiddleware(getDebug)
|
||||||
|
)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export {
|
||||||
|
debugRouter
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
async function getDebug (req: express.Request, res: express.Response) {
|
||||||
|
return res.json({
|
||||||
|
ip: req.ip
|
||||||
|
}).end()
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import { serverRedundancyRouter } from './redundancy'
|
||||||
import { serverBlocklistRouter } from './server-blocklist'
|
import { serverBlocklistRouter } from './server-blocklist'
|
||||||
import { contactRouter } from './contact'
|
import { contactRouter } from './contact'
|
||||||
import { logsRouter } from './logs'
|
import { logsRouter } from './logs'
|
||||||
|
import { debugRouter } from './debug'
|
||||||
|
|
||||||
const serverRouter = express.Router()
|
const serverRouter = express.Router()
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ serverRouter.use('/', statsRouter)
|
||||||
serverRouter.use('/', serverBlocklistRouter)
|
serverRouter.use('/', serverBlocklistRouter)
|
||||||
serverRouter.use('/', contactRouter)
|
serverRouter.use('/', contactRouter)
|
||||||
serverRouter.use('/', logsRouter)
|
serverRouter.use('/', logsRouter)
|
||||||
|
serverRouter.use('/', debugRouter)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
/* tslint:disable:no-unused-expression */
|
||||||
|
|
||||||
|
import 'mocha'
|
||||||
|
|
||||||
|
import {
|
||||||
|
createUser,
|
||||||
|
flushTests,
|
||||||
|
killallServers,
|
||||||
|
runServer,
|
||||||
|
ServerInfo,
|
||||||
|
setAccessTokensToServers,
|
||||||
|
userLogin
|
||||||
|
} from '../../../../shared/utils'
|
||||||
|
import { makeGetRequest } from '../../../../shared/utils/requests/requests'
|
||||||
|
|
||||||
|
describe('Test debug API validators', function () {
|
||||||
|
const path = '/api/v1/server/debug'
|
||||||
|
let server: ServerInfo
|
||||||
|
let userAccessToken = ''
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
this.timeout(120000)
|
||||||
|
|
||||||
|
await flushTests()
|
||||||
|
|
||||||
|
server = await runServer(1)
|
||||||
|
|
||||||
|
await setAccessTokensToServers([ server ])
|
||||||
|
|
||||||
|
const user = {
|
||||||
|
username: 'user1',
|
||||||
|
password: 'my super password'
|
||||||
|
}
|
||||||
|
await createUser(server.url, server.accessToken, user.username, user.password)
|
||||||
|
userAccessToken = await userLogin(server, user)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('When getting debug endpoint', function () {
|
||||||
|
|
||||||
|
it('Should fail with a non authenticated user', async function () {
|
||||||
|
await makeGetRequest({
|
||||||
|
url: server.url,
|
||||||
|
path,
|
||||||
|
statusCodeExpected: 401
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail with a non admin user', async function () {
|
||||||
|
await makeGetRequest({
|
||||||
|
url: server.url,
|
||||||
|
path,
|
||||||
|
token: userAccessToken,
|
||||||
|
statusCodeExpected: 403
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should succeed with the correct params', async function () {
|
||||||
|
await makeGetRequest({
|
||||||
|
url: server.url,
|
||||||
|
path,
|
||||||
|
token: server.accessToken,
|
||||||
|
query: { startDate: new Date().toISOString() },
|
||||||
|
statusCodeExpected: 200
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
killallServers([ server ])
|
||||||
|
|
||||||
|
// Keep the logs if the test failed
|
||||||
|
if (this['ok']) {
|
||||||
|
await flushTests()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
|
@ -2,6 +2,7 @@ import './accounts'
|
||||||
import './blocklist'
|
import './blocklist'
|
||||||
import './config'
|
import './config'
|
||||||
import './contact-form'
|
import './contact-form'
|
||||||
|
import './debug'
|
||||||
import './follows'
|
import './follows'
|
||||||
import './jobs'
|
import './jobs'
|
||||||
import './logs'
|
import './logs'
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export interface Debug {
|
||||||
|
ip: string
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
export * from './about.model'
|
export * from './about.model'
|
||||||
export * from './contact-form.model'
|
export * from './contact-form.model'
|
||||||
export * from './custom-config.model'
|
export * from './custom-config.model'
|
||||||
|
export * from './debug.model'
|
||||||
export * from './job.model'
|
export * from './job.model'
|
||||||
export * from './server-config.model'
|
export * from './server-config.model'
|
||||||
export * from './server-stats.model'
|
export * from './server-stats.model'
|
||||||
|
|
|
@ -7,6 +7,8 @@ export enum UserRight {
|
||||||
|
|
||||||
MANAGE_LOGS,
|
MANAGE_LOGS,
|
||||||
|
|
||||||
|
MANAGE_DEBUG,
|
||||||
|
|
||||||
MANAGE_SERVER_REDUNDANCY,
|
MANAGE_SERVER_REDUNDANCY,
|
||||||
|
|
||||||
MANAGE_VIDEO_ABUSES,
|
MANAGE_VIDEO_ABUSES,
|
||||||
|
|
Loading…
Reference in New Issue