Finished the wizard #865 (For Plex Anyway)

pull/1389/head
tidusjar 8 years ago
parent fa0e167650
commit 7294f942d9

@ -0,0 +1,34 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: OmbiClaims.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
namespace Ombi.Core.Claims
{
public static class OmbiClaims
{
public const string Admin = nameof(Admin);
}
}

@ -51,6 +51,8 @@ namespace Ombi.Core.IdentityResolver
public async Task<bool> CredentialsValid(string username, string password) public async Task<bool> CredentialsValid(string username, string password)
{ {
var user = await UserRepository.GetUser(username); var user = await UserRepository.GetUser(username);
if (user == null) return false;
var hash = HashPassword(password, user.Salt); var hash = HashPassword(password, user.Salt);
return hash.HashedPass.Equals(user.Password); return hash.HashedPass.Equals(user.Password);

@ -1,8 +1,13 @@
using System.Threading.Tasks; using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Ombi.Core.Claims;
using Ombi.Core.IdentityResolver; using Ombi.Core.IdentityResolver;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Models;
namespace Ombi.Controllers namespace Ombi.Controllers
{ {
@ -22,5 +27,36 @@ namespace Ombi.Controllers
return await IdentityManager.GetUser(this.HttpContext.User.Identity.Name); return await IdentityManager.GetUser(this.HttpContext.User.Identity.Name);
} }
/// <summary>
/// This is what the Wizard will call when creating the user for the very first time.
/// This should never be called after this.
/// The reason why we return false if users exists is that this method doesn't have any
/// authorization and could be called from anywhere.
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
[HttpPost("Wizard")]
[AllowAnonymous]
public async Task<bool> CreateWizardUser([FromBody] UserAuthModel user)
{
var users = await IdentityManager.GetUsers();
if (users.Any())
{
// No one should be calling this. Only the wizard
return false;
}
await IdentityManager.CreateUser(new UserDto
{
Username = user.Username,
UserType = UserType.LocalUser,
Claims = new List<Claim>() {new Claim(ClaimTypes.Role, OmbiClaims.Admin)},
Password = user.Password,
});
return true;
}
} }
} }

@ -0,0 +1,65 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: StatusController.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models;
namespace Ombi.Controllers
{
public class StatusController : BaseV1ApiController
{
public StatusController(ISettingsService<OmbiSettings> ombi)
{
Ombi = ombi;
}
private ISettingsService<OmbiSettings> Ombi { get; }
[AllowAnonymous]
[HttpGet]
public HttpStatusCode GetStatus()
{
return HttpStatusCode.OK;
}
[AllowAnonymous]
[HttpGet("Wizard")]
public async Task<object> WizardStatus()
{
var settings = await Ombi.GetSettingsAsync();
return new { Result = settings?.Wizard ?? false};
}
}
}

@ -20,6 +20,20 @@
<Content Include="wwwroot\app\auth\IUserLogin.ts" /> <Content Include="wwwroot\app\auth\IUserLogin.ts" />
<Content Include="wwwroot\app\login\login.component.html" /> <Content Include="wwwroot\app\login\login.component.html" />
<Content Include="wwwroot\app\login\login.component.ts" /> <Content Include="wwwroot\app\login\login.component.ts" />
<Content Include="wwwroot\app\services\identity - Copy.service.js">
<DependentUpon>identity - Copy.service.ts</DependentUpon>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\services\identity - Copy.service.js.map">
<DependentUpon>identity - Copy.service.js</DependentUpon>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\services\identity - Copy.service.ts">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\services\identity.service.js" />
<Content Include="wwwroot\app\services\identity.service.js.map" />
<Content Include="wwwroot\app\services\identity.service.ts" />
<Content Include="wwwroot\app\services\plex.service.js" /> <Content Include="wwwroot\app\services\plex.service.js" />
<Content Include="wwwroot\app\services\plex.service.js.map" /> <Content Include="wwwroot\app\services\plex.service.js.map" />
<Content Include="wwwroot\app\services\plex.service.ts"> <Content Include="wwwroot\app\services\plex.service.ts">
@ -28,6 +42,10 @@
<Content Include="wwwroot\app\services\settings.service.js" /> <Content Include="wwwroot\app\services\settings.service.js" />
<Content Include="wwwroot\app\services\settings.service.js.map" /> <Content Include="wwwroot\app\services\settings.service.js.map" />
<Content Include="wwwroot\app\services\settings.service.ts" /> <Content Include="wwwroot\app\services\settings.service.ts" />
<Content Include="wwwroot\app\services\status.service.js" />
<Content Include="wwwroot\app\services\status.service.js.map" />
<Content Include="wwwroot\app\services\status.service.ts" />
<Content Include="wwwroot\app\services\useridentity.service.ts" />
<Content Include="wwwroot\app\settings\emby\emby.component.html" /> <Content Include="wwwroot\app\settings\emby\emby.component.html" />
<Content Include="wwwroot\app\settings\emby\emby.component.js" /> <Content Include="wwwroot\app\settings\emby\emby.component.js" />
<Content Include="wwwroot\app\settings\emby\emby.component.js.map" /> <Content Include="wwwroot\app\settings\emby\emby.component.js.map" />
@ -59,11 +77,6 @@
<Content Include="wwwroot\app\wizard\createadmin\createadmin.component.js" /> <Content Include="wwwroot\app\wizard\createadmin\createadmin.component.js" />
<Content Include="wwwroot\app\wizard\createadmin\createadmin.component.js.map" /> <Content Include="wwwroot\app\wizard\createadmin\createadmin.component.js.map" />
<Content Include="wwwroot\app\wizard\createadmin\createadmin.component.ts" /> <Content Include="wwwroot\app\wizard\createadmin\createadmin.component.ts" />
<Content Include="wwwroot\app\wizard\createadmin\plex.component.js">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\createadmin\plex.component.js.map" />
<Content Include="wwwroot\app\wizard\createadmin\plex.component.ts" />
<Content Include="wwwroot\app\wizard\mediaserver\mediaserver.component.html"> <Content Include="wwwroot\app\wizard\mediaserver\mediaserver.component.html">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content> </Content>

@ -1,6 +1,6 @@
<p-growl [value]="notificationService.messages" [life]="500000"></p-growl> <p-growl [value]="notificationService.messages" [life]="500000"></p-growl>
<nav class="navbar navbar-default navbar-fixed-top"> <nav *ngIf="showNav" class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid"> <div class="container-fluid">
<div class="navbar-header"> <div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">

@ -9,5 +9,13 @@ import { AuthService } from './auth/auth.service';
}) })
export class AppComponent { export class AppComponent {
constructor(public notificationService: NotificationService, public authService : AuthService) { }; constructor(public notificationService: NotificationService, public authService: AuthService) {
this.showNav = true;
//console.log(this.route);
//if (this.route.("/Wizard/*") !== -1) {
// this.showNav = false;
//}
}
showNav :boolean;
} }

@ -23,6 +23,9 @@ import { SettingsService } from './services/settings.service';
import { AuthService } from './auth/auth.service'; import { AuthService } from './auth/auth.service';
import { AuthGuard } from './auth/auth.guard'; import { AuthGuard } from './auth/auth.guard';
import { AuthModule } from './auth/auth.module'; import { AuthModule } from './auth/auth.module';
import { IdentityService } from './services/identity.service';
import { StatusService } from './services/status.service';
// Modules // Modules
import { SettingsModule } from './settings/settings.module'; import { SettingsModule } from './settings/settings.module';
@ -69,7 +72,9 @@ const routes: Routes = [
NotificationService, NotificationService,
AuthService, AuthService,
AuthGuard, AuthGuard,
SettingsService SettingsService,
IdentityService,
StatusService
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })

@ -1,8 +1,8 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { AuthService } from '../auth/auth.service'; import { AuthService } from '../auth/auth.service';
import { StatusService } from '../services/status.service';
import { NotificationService } from '../services/notification.service'; import { NotificationService } from '../services/notification.service';
@Component({ @Component({
@ -11,7 +11,13 @@ import { NotificationService } from '../services/notification.service';
templateUrl: './login.component.html', templateUrl: './login.component.html',
}) })
export class LoginComponent { export class LoginComponent {
constructor(private authService: AuthService, private router: Router, private notify: NotificationService) { } constructor(private authService: AuthService, private router: Router, private notify: NotificationService, private status: StatusService) {
this.status.getWizardStatus().subscribe(x => {
if (!x.result) {
this.router.navigate(['Wizard']);
}
});
}
username: string; username: string;

@ -0,0 +1,17 @@
import { Injectable } from '@angular/core';
import { AuthHttp } from 'angular2-jwt';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import { ServiceAuthHelpers } from './service.helpers';
@Injectable()
export class IdentityService extends ServiceAuthHelpers {
constructor(http: AuthHttp, private regularHttp : Http) {
super(http, '/api/v1/Identity/');
}
createUser(username:string,password:string): Observable<boolean> {
return this.regularHttp.post(`${this.url}/Wizard/`, JSON.stringify({username:username, password:password}), { headers: this.headers }).map(this.extractData);
}
}

@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import { ServiceHelpers } from './service.helpers';
@Injectable()
export class StatusService extends ServiceHelpers {
constructor(http : Http) {
super(http, '/api/v1/status/');
}
getWizardStatus(): Observable<any> {
return this.http.get(`${this.url}/Wizard/`, { headers: this.headers }).map(this.extractData);
}
}

@ -1,23 +1,47 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { IdentityService } from '../../services/identity.service';
import { SettingsService } from '../../services/settings.service';
import { AuthService } from '../../auth/auth.service'; import { AuthService } from '../../auth/auth.service';
import { NotificationService } from '../../services/notification.service'; import { NotificationService } from '../../services/notification.service';
@Component({ @Component({
selector: 'ombi', selector: 'ombi',
moduleId: module.id, moduleId: module.id,
templateUrl: './plex.component.html', templateUrl: './createadmin.component.html',
}) })
export class PlexComponent { export class CreateAdminComponent {
constructor(private authService: AuthService, private notificationService: NotificationService) { } constructor(private identityService: IdentityService, private notificationService: NotificationService,
private router: Router, private auth: AuthService, private settings: SettingsService) { }
username: string; username: string;
password: string; password: string;
createUser() { createUser() {
this.identityService.createUser(this.username, this.password).subscribe(x => {
if (x) {
// Log me in.
this.auth.login({ username: this.username, password: this.password }).subscribe(c => {
localStorage.setItem("id_token", c.access_token);
// Mark that we have done the settings now
this.settings.getOmbi().subscribe(ombi => {
ombi.wizard = true;
this.settings.saveOmbi(ombi).subscribe();
this.router.navigate(['search']);
});
});
} else {
this.notificationService.error("Error in creating user",
"There was an error... You might want to put this on Github...");
}
});
} }
} }

@ -6,13 +6,16 @@ import { RouterModule, Routes } from '@angular/router';
import { WelcomeComponent } from './welcome/welcome.component'; import { WelcomeComponent } from './welcome/welcome.component';
import { MediaServerComponent } from './mediaserver/mediaserver.component'; import { MediaServerComponent } from './mediaserver/mediaserver.component';
import { PlexComponent } from './plex/plex.component'; import { PlexComponent } from './plex/plex.component';
import { CreateAdminComponent } from './createadmin/createadmin.component';
import { PlexService } from '../services/plex.service'; import { PlexService } from '../services/plex.service';
import { IdentityService } from '../services/identity.service';
const routes: Routes = [ const routes: Routes = [
{ path: 'Wizard', component: WelcomeComponent}, { path: 'Wizard', component: WelcomeComponent},
{ path: 'Wizard/MediaServer', component: MediaServerComponent}, { path: 'Wizard/MediaServer', component: MediaServerComponent},
{ path: 'Wizard/Plex', component: PlexComponent}, { path: 'Wizard/Plex', component: PlexComponent},
{ path: 'Wizard/CreateAdmin', component: CreateAdminComponent},
]; ];
@NgModule({ @NgModule({
@ -24,13 +27,15 @@ const routes: Routes = [
declarations: [ declarations: [
WelcomeComponent, WelcomeComponent,
MediaServerComponent, MediaServerComponent,
PlexComponent PlexComponent,
CreateAdminComponent
], ],
exports: [ exports: [
RouterModule RouterModule
], ],
providers: [ providers: [
PlexService PlexService,
IdentityService
], ],
}) })

Loading…
Cancel
Save