Adding a password validator

This commit is contained in:
Zoe Roux 2020-03-06 00:58:43 +01:00
parent 58f5a3b1c4
commit 93c506a3db
7 changed files with 124 additions and 10 deletions

29
package-lock.json generated
View File

@ -2895,8 +2895,7 @@
"base64-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
"dev": true
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
},
"batch": {
"version": "0.6.1",
@ -3844,6 +3843,11 @@
"randomfill": "^1.0.3"
}
},
"crypto-js": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz",
"integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q=="
},
"css-parse": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz",
@ -6993,6 +6997,24 @@
"integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
"dev": true
},
"oidc-client": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/oidc-client/-/oidc-client-1.10.1.tgz",
"integrity": "sha512-/QB5Nl7c9GmT9ir1E+OVY3+yZZnuk7Qa9ZEAJqSvDq0bAyAU9KAgeKipTEfKjGdGLTeOLy9FRWuNpULMkfZydQ==",
"requires": {
"base64-js": "^1.3.0",
"core-js": "^2.6.4",
"crypto-js": "^3.1.9-1",
"uuid": "^3.3.2"
},
"dependencies": {
"core-js": {
"version": "2.6.11",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz",
"integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg=="
}
}
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
@ -9777,8 +9799,7 @@
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"dev": true
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"validate-npm-package-license": {
"version": "3.0.4",

View File

@ -26,6 +26,7 @@
"hammerjs": "^2.0.8",
"hls.js": "^0.12.4",
"jquery": "^3.4.1",
"oidc-client": "^1.10.1",
"popper.js": "^1.16.1",
"zone.js": "~0.9.1"
},

View File

@ -28,6 +28,7 @@ import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import { MatInputModule } from "@angular/material/input";
import { MatFormFieldModule } from "@angular/material/form-field";
import {MatTabsModule} from "@angular/material/tabs";
import {PasswordValidator} from "./misc/password-validator";
@NgModule({
declarations: [
@ -41,7 +42,8 @@ import {MatTabsModule} from "@angular/material/tabs";
SearchComponent,
PeopleListComponent,
ShowsListComponent,
LoginComponent
LoginComponent,
PasswordValidator
],
imports: [
BrowserModule,

View File

@ -19,13 +19,16 @@
<br/>
<mat-form-field appearance="outline" class="w-75">
<mat-label>Password</mat-label>
<input matInput name="loginPassword" #loginPassword="ngModel" [(ngModel)]="loginInformation.password" [type]="hidePassword ? 'password' : 'text'" required>
<input matInput name="loginPassword" #loginPassword="ngModel" [(ngModel)]="loginInformation.password" [type]="hidePassword ? 'password' : 'text'" required passwordValidator>
<button mat-icon-button matSuffix (click)="hidePassword = !hidePassword" [attr.aria-label]="'Hide password'" [attr.aria-pressed]="hidePassword">
<mat-icon>{{hidePassword ? 'visibility_off' : 'visibility'}}</mat-icon>
</button>
<mat-error *ngIf="loginPassword.hasError('required')">
A password is <strong>required</strong>
</mat-error>
<mat-error *ngIf="loginPassword.hasError('passwordError')">
Error: {{signinPassword.getError("passwordError")["error"]}}
</mat-error>
</mat-form-field>
</form>
</mat-card-content>
@ -60,13 +63,16 @@
<br/>
<mat-form-field appearance="outline" class="w-75">
<mat-label>Password</mat-label>
<input matInput name="signinPassword" #signinPassword="ngModel" [(ngModel)]="signinInformation.password" [type]="hidePassword ? 'password' : 'text'" required>
<input matInput name="signinPassword" #signinPassword="ngModel" [(ngModel)]="signinInformation.password" [type]="hidePassword ? 'password' : 'text'" required passwordValidator>
<button mat-icon-button matSuffix (click)="hidePassword = !hidePassword" [attr.aria-label]="'Hide password'" [attr.aria-pressed]="hidePassword">
<mat-icon>{{hidePassword ? 'visibility_off' : 'visibility'}}</mat-icon>
</button>
<mat-error *ngIf="signinPassword.hasError('required')">
A password is <strong>required</strong>
</mat-error>
<mat-error *ngIf="signinPassword.hasError('passwordError')">
Error: {{signinPassword.getError("passwordError")["error"]}}
</mat-error>
</mat-form-field>
</mat-card-content>
<div fxFlexAlign="end" align="end" style="text-align: end">

View File

@ -1,5 +1,5 @@
import { Component, OnInit } from '@angular/core';
import {FormControl, FormGroup, Validators} from "@angular/forms";
import {AuthService} from "../services/auth.service";
@Component({
selector: 'app-login',
@ -12,7 +12,7 @@ export class LoginComponent
signinInformation: {email: string, username: string, password: string} = {email: "", username: "", password: ""};
hidePassword: boolean = true;
constructor() { }
constructor(private authService: AuthService) { }
async login()
{
@ -21,6 +21,13 @@ export class LoginComponent
async signin()
{
console.log("Signing in")
this.authService.register(this.signinInformation)
.subscribe(result =>
{
console.log("Sucess: " + result);
}, error => {
console.log("Register error: " + error);
});
console.log("Register returned");
}
}

View File

@ -0,0 +1,26 @@
import {AbstractControl, NG_VALIDATORS, Validator} from "@angular/forms";
import {Directive} from "@angular/core";
@Directive({
selector: "[passwordValidator]",
providers: [{provide: NG_VALIDATORS, useExisting: PasswordValidator, multi: true}]
})
export class PasswordValidator implements Validator
{
validate(control: AbstractControl): {[key: string]: any} | null
{
if (!control.value)
return null;
if (!/[a-z]/.test(control.value))
return {"passwordError": {error: "The password must contains a lowercase letter."}};
if (!/[A-Z]/.test(control.value))
return {"passwordError": {error: "The password must contains an uppercase letter."}};
if (!/[0-9]/.test(control.value))
return {"passwordError": {error: "The password must contains a digit."}};
if (!/\W/.test(control.value))
return {"passwordError": {error: "The password must contains a non-alphanumeric character."}};
if (control.value.toString().length < 6)
return {"passwordError": {error: "Password must be at least 6 character long."}};
return null;
}
}

View File

@ -0,0 +1,51 @@
import { Injectable } from '@angular/core';
import { UserManager, UserManagerSettings, User } from 'oidc-client';
import {HttpClient} from "@angular/common/http";
import { catchError } from 'rxjs/operators';
import {EMPTY} from "rxjs";
import {MatSnackBar} from "@angular/material/snack-bar";
@Injectable({
providedIn: 'root'
})
export class AuthService
{
user: User | null;
private _userManager = new UserManager(this.getClientSettings());
constructor(private http: HttpClient, private snackBar: MatSnackBar)
{
this._userManager.getUser().then(user =>
{
this.user = user;
if (user)
console.log("Logged in as: " + user.profile.name);
});
}
login()
{
return this._userManager.signinRedirect();
}
register(userRegistration: any)
{
return this.http.post("/api/account/register", userRegistration).pipe(catchError((error =>
{
console.log(error.status + " - " + error.message);
this.snackBar.open(`An unknown error occured: ${error.message}.`, null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
return EMPTY;
})));
}
getClientSettings(): UserManagerSettings
{
return {
authority: "",
client_id: "kyoo.webapp",
redirect_uri: "/logged",
response_type:"id_token token",
scope:"openid profile kyoo.read"
};
}
}