Add debug component to help admins to fix IP issues

pull/1765/head
Chocobozzz 2019-04-11 10:56:29 +02:00
parent 2b3f1919fd
commit 5d79474cc6
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
19 changed files with 242 additions and 10 deletions

View File

@ -16,7 +16,7 @@
Configuration
</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
</a>
</div>

View File

@ -24,15 +24,19 @@ export class AdminComponent {
return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
}
hasJobsRight () {
return this.auth.getUser().hasRight(UserRight.MANAGE_JOBS)
hasConfigRight () {
return this.auth.getUser().hasRight(UserRight.MANAGE_CONFIGURATION)
}
hasLogsRight () {
return this.auth.getUser().hasRight(UserRight.MANAGE_LOGS)
}
hasConfigRight () {
return this.auth.getUser().hasRight(UserRight.MANAGE_CONFIGURATION)
hasJobsRight () {
return this.auth.getUser().hasRight(UserRight.MANAGE_JOBS)
}
hasDebugRight () {
return this.auth.getUser().hasRight(UserRight.MANAGE_DEBUG)
}
}

View File

@ -20,6 +20,7 @@ import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service
import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist'
import { JobsComponent } from '@app/+admin/system/jobs/jobs.component'
import { JobService, LogsComponent, LogsService, SystemComponent } from '@app/+admin/system'
import { DebugComponent, DebugService } from '@app/+admin/system/debug'
@NgModule({
imports: [
@ -54,6 +55,7 @@ import { JobService, LogsComponent, LogsService, SystemComponent } from '@app/+a
SystemComponent,
JobsComponent,
LogsComponent,
DebugComponent,
ConfigComponent,
EditCustomConfigComponent
@ -68,6 +70,7 @@ import { JobService, LogsComponent, LogsService, SystemComponent } from '@app/+a
RedundancyService,
JobService,
LogsService,
DebugService,
ConfigService
]
})

View File

@ -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>

View File

@ -0,0 +1,6 @@
@import '_variables';
@import '_mixins';
.root {
font-size: 14px;
}

View File

@ -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)
)
}
}

View File

@ -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))
)
}
}

View File

@ -0,0 +1,2 @@
export * from './debug.component'
export * from './debug.service'

View File

@ -9,7 +9,7 @@ import { LogLevel } from '@shared/models/server/log-level.type'
@Injectable()
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 (
private authHttp: HttpClient,
@ -17,14 +17,14 @@ export class LogsService {
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()
params = params.append('startDate', startDate)
params = params.append('level', level)
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(
map(rows => rows.map(r => new LogRow(r))),
catchError(err => this.restExtractor.handleError(err))

View File

@ -2,9 +2,11 @@
<div i18n class="form-sub-title">System</div>
<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>

View File

@ -1,8 +1,24 @@
import { Component } from '@angular/core'
import { UserRight } from '@shared/models'
import { AuthService } from '@app/core'
@Component({
templateUrl: './system.component.html',
styleUrls: [ './system.component.scss' ]
})
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)
}
}

View File

@ -4,6 +4,7 @@ import { UserRight } from '../../../../../shared'
import { JobsComponent } from '@app/+admin/system/jobs/jobs.component'
import { LogsComponent } from '@app/+admin/system/logs'
import { SystemComponent } from '@app/+admin/system/system.component'
import { DebugComponent } from '@app/+admin/system/debug'
export const SystemRoutes: Routes = [
{
@ -38,6 +39,17 @@ export const SystemRoutes: Routes = [
title: 'Logs'
}
}
},
{
path: 'debug',
canActivate: [ UserRightGuard ],
component: DebugComponent,
data: {
meta: {
userRight: UserRight.MANAGE_DEBUG,
title: 'Debug'
}
}
}
]
}

View File

@ -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()
}

View File

@ -5,6 +5,7 @@ import { serverRedundancyRouter } from './redundancy'
import { serverBlocklistRouter } from './server-blocklist'
import { contactRouter } from './contact'
import { logsRouter } from './logs'
import { debugRouter } from './debug'
const serverRouter = express.Router()
@ -14,6 +15,7 @@ serverRouter.use('/', statsRouter)
serverRouter.use('/', serverBlocklistRouter)
serverRouter.use('/', contactRouter)
serverRouter.use('/', logsRouter)
serverRouter.use('/', debugRouter)
// ---------------------------------------------------------------------------

View File

@ -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()
}
})
})

View File

@ -2,6 +2,7 @@ import './accounts'
import './blocklist'
import './config'
import './contact-form'
import './debug'
import './follows'
import './jobs'
import './logs'

View File

@ -0,0 +1,3 @@
export interface Debug {
ip: string
}

View File

@ -1,6 +1,7 @@
export * from './about.model'
export * from './contact-form.model'
export * from './custom-config.model'
export * from './debug.model'
export * from './job.model'
export * from './server-config.model'
export * from './server-stats.model'

View File

@ -7,6 +7,8 @@ export enum UserRight {
MANAGE_LOGS,
MANAGE_DEBUG,
MANAGE_SERVER_REDUNDANCY,
MANAGE_VIDEO_ABUSES,