@triangular/password-checker 5.0.0 → 8.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/esm2020/lib/password-checker-lib.directive.mjs +79 -0
- package/esm2020/lib/password-checker-lib.module.mjs +30 -0
- package/{esm2015/lib/password-checker.config.js → esm2020/lib/password-checker.config.mjs} +0 -0
- package/{esm2015/public_api.js → esm2020/public_api.mjs} +0 -0
- package/esm2020/triangular-password-checker.mjs +5 -0
- package/fesm2015/triangular-password-checker.mjs +119 -0
- package/fesm2015/triangular-password-checker.mjs.map +1 -0
- package/fesm2020/triangular-password-checker.mjs +117 -0
- package/fesm2020/triangular-password-checker.mjs.map +1 -0
- package/lib/password-checker-lib.directive.d.ts +3 -0
- package/lib/password-checker-lib.module.d.ts +6 -0
- package/package.json +22 -10
- package/triangular-password-checker.d.ts +1 -1
- package/bundles/triangular-password-checker.umd.js +0 -113
- package/bundles/triangular-password-checker.umd.js.map +0 -1
- package/bundles/triangular-password-checker.umd.min.js +0 -2
- package/bundles/triangular-password-checker.umd.min.js.map +0 -1
- package/esm2015/lib/password-checker-lib.directive.js +0 -67
- package/esm2015/lib/password-checker-lib.module.js +0 -25
- package/esm2015/triangular-password-checker.js +0 -6
- package/fesm2015/triangular-password-checker.js +0 -100
- package/fesm2015/triangular-password-checker.js.map +0 -1
- package/triangular-password-checker.metadata.json +0 -1
package/README.md
CHANGED
|
@@ -14,6 +14,9 @@ Supported Angular Versions
|
|
|
14
14
|
| 8.x | 3.0.0 |
|
|
15
15
|
| 9.x | 4.0.0 |
|
|
16
16
|
| 10.x | 5.0.0 |
|
|
17
|
+
| 11.x | 6.0.0 |
|
|
18
|
+
| 12.x | 7.0.0 |
|
|
19
|
+
| 13.x | 8.0.1 |
|
|
17
20
|
|
|
18
21
|
### Step 1: Install
|
|
19
22
|
|
|
@@ -168,6 +171,12 @@ We use [SemVer](http://semver.org/) for versioning.
|
|
|
168
171
|
- 1.0.0: Initial Release
|
|
169
172
|
- 2.2.0: Code Improvements and Angular 7.x
|
|
170
173
|
- 3.0.0: Angular 8.x
|
|
174
|
+
- 4.0.0: Angular 9.x
|
|
175
|
+
- 5.0.0: Angular 10.x
|
|
176
|
+
- 6.0.0: Angular 11.x
|
|
177
|
+
- 7.0.0: Angular 12.x
|
|
178
|
+
- 8.0.0: Angular 13.x
|
|
179
|
+
- 8.0.1: Upgrade rxjs to 7.4
|
|
171
180
|
|
|
172
181
|
## Authors
|
|
173
182
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { timer } from 'rxjs';
|
|
2
|
+
import { map, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { NG_ASYNC_VALIDATORS } from '@angular/forms';
|
|
4
|
+
import { Directive, Inject, Input, Optional } from '@angular/core';
|
|
5
|
+
import sha1 from 'crypto-js/sha1';
|
|
6
|
+
import { PasswordCheckerConfigValue } from './password-checker.config';
|
|
7
|
+
import * as i0 from "@angular/core";
|
|
8
|
+
import * as i1 from "@angular/common/http";
|
|
9
|
+
export class PasswordCheckerLibDirective {
|
|
10
|
+
constructor(http, config) {
|
|
11
|
+
this.http = http;
|
|
12
|
+
if (!config) {
|
|
13
|
+
// default initialization in constructor didn't work.
|
|
14
|
+
// conflict with @Optional()?
|
|
15
|
+
config = {};
|
|
16
|
+
}
|
|
17
|
+
this.pwnedPasswordApi =
|
|
18
|
+
config.pwnedPasswordApi
|
|
19
|
+
|| 'https://api.pwnedpasswords.com/range/';
|
|
20
|
+
this.pwnedPasswordMinimumOccurrenceForError =
|
|
21
|
+
config.pwnedPasswordMinimumOccurrenceForError
|
|
22
|
+
|| 1;
|
|
23
|
+
this.pwnedPasswordApiCallDebounceTime =
|
|
24
|
+
config.pwnedPasswordApiCallDebounceTime
|
|
25
|
+
|| 400;
|
|
26
|
+
}
|
|
27
|
+
validate(control) {
|
|
28
|
+
const pw = ''.concat(control.value);
|
|
29
|
+
return timer(this.pwnedPasswordApiCallDebounceTime).pipe(map(() => {
|
|
30
|
+
const pwSha1 = sha1(pw).toString().toUpperCase();
|
|
31
|
+
return {
|
|
32
|
+
firstPart: pwSha1.substring(0, 5),
|
|
33
|
+
lastPart: pwSha1.substring(5),
|
|
34
|
+
};
|
|
35
|
+
}), switchMap((hash) => this.http.get(`${this.pwnedPasswordApi}${hash.firstPart}`, { responseType: 'text' }).pipe(map(passwords => passwords.split(/[\r\n]+/)), map(passwords => passwords.map((password) => {
|
|
36
|
+
const split = password.split(':');
|
|
37
|
+
return {
|
|
38
|
+
hash: split[0],
|
|
39
|
+
count: parseInt(split[1], 10),
|
|
40
|
+
};
|
|
41
|
+
})), map(passwords => passwords.find(password => password.hash === hash.lastPart)))), map(password => password && password.count >= this.pwnedPasswordMinimumOccurrenceForError
|
|
42
|
+
? { pwnedPasswordOccurrence: password.count }
|
|
43
|
+
: null));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
PasswordCheckerLibDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerLibDirective, deps: [{ token: i1.HttpClient }, { token: PasswordCheckerConfigValue, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
47
|
+
PasswordCheckerLibDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.0.2", type: PasswordCheckerLibDirective, selector: "[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]", inputs: { pwnedPasswordApi: "pwnedPasswordApi", pwnedPasswordMinimumOccurrenceForError: "pwnedPasswordMinimumOccurrenceForError", pwnedPasswordApiCallDebounceTime: "pwnedPasswordApiCallDebounceTime" }, providers: [
|
|
48
|
+
{
|
|
49
|
+
provide: NG_ASYNC_VALIDATORS,
|
|
50
|
+
useExisting: PasswordCheckerLibDirective,
|
|
51
|
+
multi: true,
|
|
52
|
+
},
|
|
53
|
+
], ngImport: i0 });
|
|
54
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerLibDirective, decorators: [{
|
|
55
|
+
type: Directive,
|
|
56
|
+
args: [{
|
|
57
|
+
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
58
|
+
selector: '[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]',
|
|
59
|
+
providers: [
|
|
60
|
+
{
|
|
61
|
+
provide: NG_ASYNC_VALIDATORS,
|
|
62
|
+
useExisting: PasswordCheckerLibDirective,
|
|
63
|
+
multi: true,
|
|
64
|
+
},
|
|
65
|
+
]
|
|
66
|
+
}]
|
|
67
|
+
}], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: undefined, decorators: [{
|
|
68
|
+
type: Optional
|
|
69
|
+
}, {
|
|
70
|
+
type: Inject,
|
|
71
|
+
args: [PasswordCheckerConfigValue]
|
|
72
|
+
}] }]; }, propDecorators: { pwnedPasswordApi: [{
|
|
73
|
+
type: Input
|
|
74
|
+
}], pwnedPasswordMinimumOccurrenceForError: [{
|
|
75
|
+
type: Input
|
|
76
|
+
}], pwnedPasswordApiCallDebounceTime: [{
|
|
77
|
+
type: Input
|
|
78
|
+
}] } });
|
|
79
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFzc3dvcmQtY2hlY2tlci1saWIuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvcGFzc3dvcmQtY2hlY2tlci1saWIvc3JjL2xpYi9wYXNzd29yZC1jaGVja2VyLWxpYi5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFjLEtBQUssRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN6QyxPQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2hELE9BQU8sRUFBbUMsbUJBQW1CLEVBQW9CLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEcsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUVuRSxPQUFPLElBQUksTUFBTSxnQkFBZ0IsQ0FBQztBQUNsQyxPQUFPLEVBQWtDLDBCQUEwQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7OztBQWF2RyxNQUFNLE9BQU8sMkJBQTJCO0lBT3RDLFlBQ1UsSUFBZ0IsRUFDd0IsTUFBc0M7UUFEOUUsU0FBSSxHQUFKLElBQUksQ0FBWTtRQUl4QixJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ1gscURBQXFEO1lBQ3JELDZCQUE2QjtZQUM3QixNQUFNLEdBQUcsRUFBRSxDQUFDO1NBQ2I7UUFFRCxJQUFJLENBQUMsZ0JBQWdCO1lBQ25CLE1BQU0sQ0FBQyxnQkFBZ0I7bUJBQ3BCLHVDQUF1QyxDQUFDO1FBQzdDLElBQUksQ0FBQyxzQ0FBc0M7WUFDekMsTUFBTSxDQUFDLHNDQUFzQzttQkFDMUMsQ0FBQyxDQUFDO1FBQ1AsSUFBSSxDQUFDLGdDQUFnQztZQUNuQyxNQUFNLENBQUMsZ0NBQWdDO21CQUNwQyxHQUFHLENBQUM7SUFDWCxDQUFDO0lBRUQsUUFBUSxDQUFDLE9BQXdCO1FBQy9CLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRXBDLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDLElBQUksQ0FDdEQsR0FBRyxDQUFDLEdBQUcsRUFBRTtZQUNQLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUVqRCxPQUFPO2dCQUNMLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQ2pDLFFBQVEsRUFBRSxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQzthQUM5QixDQUFDO1FBQ0osQ0FBQyxDQUFDLEVBQ0YsU0FBUyxDQUNQLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FDckIsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLFNBQVMsRUFBRSxFQUFHLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxDQUNyRSxDQUFDLElBQUksQ0FDTixHQUFHLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQzVDLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRTtZQUN4QyxNQUFNLEtBQUssR0FBSSxRQUFRLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBRW5DLE9BQU87Z0JBQ0wsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7Z0JBQ2QsS0FBSyxFQUFFLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDO2FBQzlCLENBQUM7UUFDSixDQUFDLENBQ0YsQ0FBQyxFQUNGLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxLQUFLLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUM5RSxDQUNGLEVBQ0QsR0FBRyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsUUFBUSxJQUFJLFFBQVEsQ0FBQyxLQUFLLElBQUksSUFBSSxDQUFDLHNDQUFzQztZQUN2RixDQUFDLENBQUMsRUFBRSx1QkFBdUIsRUFBRSxRQUFRLENBQUMsS0FBSyxFQUFFO1lBQzdDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FDVixDQUFDO0lBQ0osQ0FBQzs7d0hBOURVLDJCQUEyQiw0Q0FTaEIsMEJBQTBCOzRHQVRyQywyQkFBMkIsdVZBUjNCO1FBQ0w7WUFDRSxPQUFPLEVBQUUsbUJBQW1CO1lBQzVCLFdBQVcsRUFBRSwyQkFBMkI7WUFDeEMsS0FBSyxFQUFFLElBQUk7U0FDWjtLQUNGOzJGQUVNLDJCQUEyQjtrQkFYdkMsU0FBUzttQkFBQztvQkFDVCwrREFBK0Q7b0JBQy9ELFFBQVEsRUFBRSxvSEFBb0g7b0JBQzlILFNBQVMsRUFBRTt3QkFDTDs0QkFDRSxPQUFPLEVBQUUsbUJBQW1COzRCQUM1QixXQUFXLDZCQUE2Qjs0QkFDeEMsS0FBSyxFQUFFLElBQUk7eUJBQ1o7cUJBQ0Y7aUJBQ047OzBCQVVJLFFBQVE7OzBCQUFJLE1BQU07MkJBQUMsMEJBQTBCOzRDQU52QyxnQkFBZ0I7c0JBQXhCLEtBQUs7Z0JBQ0csc0NBQXNDO3NCQUE5QyxLQUFLO2dCQUNHLGdDQUFnQztzQkFBeEMsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE9ic2VydmFibGUsIHRpbWVyIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBtYXAsIHN3aXRjaE1hcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgQXN5bmNWYWxpZGF0b3IsIE5HX0FTWU5DX1ZBTElEQVRPUlMsIFZhbGlkYXRpb25FcnJvcnMgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBEaXJlY3RpdmUsIEluamVjdCwgSW5wdXQsIE9wdGlvbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBIdHRwQ2xpZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHNoYTEgZnJvbSAnY3J5cHRvLWpzL3NoYTEnO1xuaW1wb3J0IHsgUGFydGlhbCwgUGFzc3dvcmRDaGVja2VyQ29uZmlnLCBQYXNzd29yZENoZWNrZXJDb25maWdWYWx1ZSB9IGZyb20gJy4vcGFzc3dvcmQtY2hlY2tlci5jb25maWcnO1xuXG5ARGlyZWN0aXZlKHtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lICBAYW5ndWxhci1lc2xpbnQvZGlyZWN0aXZlLXNlbGVjdG9yXG4gIHNlbGVjdG9yOiAnW3B3bmVkUGFzc3dvcmRWYWxpZGF0b3JdW2Zvcm1Db250cm9sTmFtZV0sIFtwd25lZFBhc3N3b3JkVmFsaWRhdG9yXVtuZ01vZGVsXSxbcHduZWRQYXNzd29yZFZhbGlkYXRvcl1bZm9ybUNvbnRyb2xdJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBwcm92aWRlOiBOR19BU1lOQ19WQUxJREFUT1JTLFxuICAgICAgICAgIHVzZUV4aXN0aW5nOiBQYXNzd29yZENoZWNrZXJMaWJEaXJlY3RpdmUsXG4gICAgICAgICAgbXVsdGk6IHRydWUsXG4gICAgICAgIH0sXG4gICAgICBdXG59KVxuZXhwb3J0IGNsYXNzIFBhc3N3b3JkQ2hlY2tlckxpYkRpcmVjdGl2ZSBpbXBsZW1lbnRzIEFzeW5jVmFsaWRhdG9yIHtcbiAgcHJpdmF0ZSBwd25lZFBhc3N3b3JkTWluaW11bU9jY3VycmVuY2VGb3JFcnJvclZhbHVlOiBudW1iZXI7XG5cbiAgQElucHV0KCkgcHduZWRQYXNzd29yZEFwaTogc3RyaW5nO1xuICBASW5wdXQoKSBwd25lZFBhc3N3b3JkTWluaW11bU9jY3VycmVuY2VGb3JFcnJvcjogbnVtYmVyO1xuICBASW5wdXQoKSBwd25lZFBhc3N3b3JkQXBpQ2FsbERlYm91bmNlVGltZTogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgaHR0cDogSHR0cENsaWVudCxcbiAgICBAT3B0aW9uYWwoKSBASW5qZWN0KFBhc3N3b3JkQ2hlY2tlckNvbmZpZ1ZhbHVlKSBjb25maWc6IFBhcnRpYWw8UGFzc3dvcmRDaGVja2VyQ29uZmlnPixcbiAgICApIHtcblxuICAgIGlmICghY29uZmlnKSB7XG4gICAgICAvLyBkZWZhdWx0IGluaXRpYWxpemF0aW9uIGluIGNvbnN0cnVjdG9yIGRpZG4ndCB3b3JrLlxuICAgICAgLy8gY29uZmxpY3Qgd2l0aCBAT3B0aW9uYWwoKT9cbiAgICAgIGNvbmZpZyA9IHt9O1xuICAgIH1cblxuICAgIHRoaXMucHduZWRQYXNzd29yZEFwaSA9XG4gICAgICBjb25maWcucHduZWRQYXNzd29yZEFwaVxuICAgICAgfHwgJ2h0dHBzOi8vYXBpLnB3bmVkcGFzc3dvcmRzLmNvbS9yYW5nZS8nO1xuICAgIHRoaXMucHduZWRQYXNzd29yZE1pbmltdW1PY2N1cnJlbmNlRm9yRXJyb3IgPVxuICAgICAgY29uZmlnLnB3bmVkUGFzc3dvcmRNaW5pbXVtT2NjdXJyZW5jZUZvckVycm9yXG4gICAgICB8fCAxO1xuICAgIHRoaXMucHduZWRQYXNzd29yZEFwaUNhbGxEZWJvdW5jZVRpbWUgPVxuICAgICAgY29uZmlnLnB3bmVkUGFzc3dvcmRBcGlDYWxsRGVib3VuY2VUaW1lXG4gICAgICB8fCA0MDA7XG4gIH1cblxuICB2YWxpZGF0ZShjb250cm9sOiBBYnN0cmFjdENvbnRyb2wpOiBPYnNlcnZhYmxlPFZhbGlkYXRpb25FcnJvcnN8bnVsbD4ge1xuICAgIGNvbnN0IHB3ID0gJycuY29uY2F0KGNvbnRyb2wudmFsdWUpO1xuXG4gICAgcmV0dXJuIHRpbWVyKHRoaXMucHduZWRQYXNzd29yZEFwaUNhbGxEZWJvdW5jZVRpbWUpLnBpcGUoXG4gICAgICBtYXAoKCkgPT4ge1xuICAgICAgICBjb25zdCBwd1NoYTEgPSBzaGExKHB3KS50b1N0cmluZygpLnRvVXBwZXJDYXNlKCk7XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBmaXJzdFBhcnQ6IHB3U2hhMS5zdWJzdHJpbmcoMCwgNSksXG4gICAgICAgICAgbGFzdFBhcnQ6IHB3U2hhMS5zdWJzdHJpbmcoNSksXG4gICAgICAgIH07XG4gICAgICB9KSxcbiAgICAgIHN3aXRjaE1hcChcbiAgICAgICAgKGhhc2gpID0+IHRoaXMuaHR0cC5nZXQoXG4gICAgICAgICAgYCR7dGhpcy5wd25lZFBhc3N3b3JkQXBpfSR7aGFzaC5maXJzdFBhcnR9YCwgIHsgcmVzcG9uc2VUeXBlOiAndGV4dCcgfVxuICAgICAgICAgICkucGlwZShcbiAgICAgICAgICBtYXAocGFzc3dvcmRzID0+IHBhc3N3b3Jkcy5zcGxpdCgvW1xcclxcbl0rLykpLFxuICAgICAgICAgIG1hcChwYXNzd29yZHMgPT4gcGFzc3dvcmRzLm1hcCgocGFzc3dvcmQpID0+IHtcbiAgICAgICAgICAgICAgY29uc3Qgc3BsaXQgPSAgcGFzc3dvcmQuc3BsaXQoJzonKTtcblxuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGhhc2g6IHNwbGl0WzBdLFxuICAgICAgICAgICAgICAgIGNvdW50OiBwYXJzZUludChzcGxpdFsxXSwgMTApLFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICkpLFxuICAgICAgICAgIG1hcChwYXNzd29yZHMgPT4gcGFzc3dvcmRzLmZpbmQocGFzc3dvcmQgPT4gcGFzc3dvcmQuaGFzaCA9PT0gaGFzaC5sYXN0UGFydCkpLFxuICAgICAgICApLFxuICAgICAgKSxcbiAgICAgIG1hcChwYXNzd29yZCA9PiBwYXNzd29yZCAmJiBwYXNzd29yZC5jb3VudCA+PSB0aGlzLnB3bmVkUGFzc3dvcmRNaW5pbXVtT2NjdXJyZW5jZUZvckVycm9yXG4gICAgICAgID8geyBwd25lZFBhc3N3b3JkT2NjdXJyZW5jZTogcGFzc3dvcmQuY291bnQgfVxuICAgICAgICA6IG51bGwpLFxuICAgICk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { PasswordCheckerLibDirective } from './password-checker-lib.directive';
|
|
3
|
+
import { HttpClientModule } from '@angular/common/http';
|
|
4
|
+
import { PasswordCheckerConfigValue } from './password-checker.config';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
export class PasswordCheckerModule {
|
|
7
|
+
static forRoot(config = {}) {
|
|
8
|
+
return {
|
|
9
|
+
ngModule: PasswordCheckerModule,
|
|
10
|
+
providers: [
|
|
11
|
+
{
|
|
12
|
+
provide: PasswordCheckerConfigValue,
|
|
13
|
+
useValue: config,
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
PasswordCheckerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
20
|
+
PasswordCheckerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, declarations: [PasswordCheckerLibDirective], imports: [HttpClientModule], exports: [PasswordCheckerLibDirective] });
|
|
21
|
+
PasswordCheckerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, imports: [[HttpClientModule]] });
|
|
22
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, decorators: [{
|
|
23
|
+
type: NgModule,
|
|
24
|
+
args: [{
|
|
25
|
+
declarations: [PasswordCheckerLibDirective],
|
|
26
|
+
imports: [HttpClientModule],
|
|
27
|
+
exports: [PasswordCheckerLibDirective]
|
|
28
|
+
}]
|
|
29
|
+
}] });
|
|
30
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFzc3dvcmQtY2hlY2tlci1saWIubW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvcGFzc3dvcmQtY2hlY2tlci1saWIvc3JjL2xpYi9wYXNzd29yZC1jaGVja2VyLWxpYi5tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUF1QixRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDOUQsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDL0UsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDeEQsT0FBTyxFQUFrQywwQkFBMEIsRUFBRSxNQUFNLDJCQUEyQixDQUFDOztBQU92RyxNQUFNLE9BQU8scUJBQXFCO0lBQ2hDLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBeUMsRUFBRTtRQUN4RCxPQUFPO1lBQ0wsUUFBUSxFQUFFLHFCQUFxQjtZQUMvQixTQUFTLEVBQUU7Z0JBQ1Q7b0JBQ0UsT0FBTyxFQUFFLDBCQUEwQjtvQkFDbkMsUUFBUSxFQUFFLE1BQU07aUJBQ2pCO2FBQ0Y7U0FDRixDQUFDO0lBQ0osQ0FBQzs7a0hBWFUscUJBQXFCO21IQUFyQixxQkFBcUIsaUJBSmpCLDJCQUEyQixhQUNoQyxnQkFBZ0IsYUFDaEIsMkJBQTJCO21IQUUxQixxQkFBcUIsWUFIdkIsQ0FBQyxnQkFBZ0IsQ0FBQzsyRkFHaEIscUJBQXFCO2tCQUxqQyxRQUFRO21CQUFDO29CQUNSLFlBQVksRUFBRSxDQUFDLDJCQUEyQixDQUFDO29CQUMzQyxPQUFPLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQztvQkFDM0IsT0FBTyxFQUFFLENBQUMsMkJBQTJCLENBQUM7aUJBQ3ZDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTW9kdWxlV2l0aFByb3ZpZGVycywgTmdNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFBhc3N3b3JkQ2hlY2tlckxpYkRpcmVjdGl2ZSB9IGZyb20gJy4vcGFzc3dvcmQtY2hlY2tlci1saWIuZGlyZWN0aXZlJztcbmltcG9ydCB7IEh0dHBDbGllbnRNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBQYXJ0aWFsLCBQYXNzd29yZENoZWNrZXJDb25maWcsIFBhc3N3b3JkQ2hlY2tlckNvbmZpZ1ZhbHVlIH0gZnJvbSAnLi9wYXNzd29yZC1jaGVja2VyLmNvbmZpZyc7XG5cbkBOZ01vZHVsZSh7XG4gIGRlY2xhcmF0aW9uczogW1Bhc3N3b3JkQ2hlY2tlckxpYkRpcmVjdGl2ZV0sXG4gIGltcG9ydHM6IFtIdHRwQ2xpZW50TW9kdWxlXSxcbiAgZXhwb3J0czogW1Bhc3N3b3JkQ2hlY2tlckxpYkRpcmVjdGl2ZV1cbn0pXG5leHBvcnQgY2xhc3MgUGFzc3dvcmRDaGVja2VyTW9kdWxlIHtcbiAgc3RhdGljIGZvclJvb3QoY29uZmlnOiBQYXJ0aWFsPFBhc3N3b3JkQ2hlY2tlckNvbmZpZz4gPSB7fSk6IE1vZHVsZVdpdGhQcm92aWRlcnM8UGFzc3dvcmRDaGVja2VyTW9kdWxlPiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5nTW9kdWxlOiBQYXNzd29yZENoZWNrZXJNb2R1bGUsXG4gICAgICBwcm92aWRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIHByb3ZpZGU6IFBhc3N3b3JkQ2hlY2tlckNvbmZpZ1ZhbHVlLFxuICAgICAgICAgIHVzZVZhbHVlOiBjb25maWcsXG4gICAgICAgIH1cbiAgICAgIF1cbiAgICB9O1xuICB9XG59XG4iXX0=
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated bundle index. Do not edit.
|
|
3
|
+
*/
|
|
4
|
+
export * from './public_api';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJpYW5ndWxhci1wYXNzd29yZC1jaGVja2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcHJvamVjdHMvcGFzc3dvcmQtY2hlY2tlci1saWIvc3JjL3RyaWFuZ3VsYXItcGFzc3dvcmQtY2hlY2tlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsY0FBYyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL3B1YmxpY19hcGknO1xuIl19
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { timer } from 'rxjs';
|
|
2
|
+
import { map, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { NG_ASYNC_VALIDATORS } from '@angular/forms';
|
|
4
|
+
import * as i0 from '@angular/core';
|
|
5
|
+
import { InjectionToken, Directive, Optional, Inject, Input, NgModule } from '@angular/core';
|
|
6
|
+
import sha1 from 'crypto-js/sha1';
|
|
7
|
+
import * as i1 from '@angular/common/http';
|
|
8
|
+
import { HttpClientModule } from '@angular/common/http';
|
|
9
|
+
|
|
10
|
+
const PasswordCheckerConfigValue = new InjectionToken('PASSWORD_CHECKER_CONFIG');
|
|
11
|
+
|
|
12
|
+
class PasswordCheckerLibDirective {
|
|
13
|
+
constructor(http, config) {
|
|
14
|
+
this.http = http;
|
|
15
|
+
if (!config) {
|
|
16
|
+
// default initialization in constructor didn't work.
|
|
17
|
+
// conflict with @Optional()?
|
|
18
|
+
config = {};
|
|
19
|
+
}
|
|
20
|
+
this.pwnedPasswordApi =
|
|
21
|
+
config.pwnedPasswordApi
|
|
22
|
+
|| 'https://api.pwnedpasswords.com/range/';
|
|
23
|
+
this.pwnedPasswordMinimumOccurrenceForError =
|
|
24
|
+
config.pwnedPasswordMinimumOccurrenceForError
|
|
25
|
+
|| 1;
|
|
26
|
+
this.pwnedPasswordApiCallDebounceTime =
|
|
27
|
+
config.pwnedPasswordApiCallDebounceTime
|
|
28
|
+
|| 400;
|
|
29
|
+
}
|
|
30
|
+
validate(control) {
|
|
31
|
+
const pw = ''.concat(control.value);
|
|
32
|
+
return timer(this.pwnedPasswordApiCallDebounceTime).pipe(map(() => {
|
|
33
|
+
const pwSha1 = sha1(pw).toString().toUpperCase();
|
|
34
|
+
return {
|
|
35
|
+
firstPart: pwSha1.substring(0, 5),
|
|
36
|
+
lastPart: pwSha1.substring(5),
|
|
37
|
+
};
|
|
38
|
+
}), switchMap((hash) => this.http.get(`${this.pwnedPasswordApi}${hash.firstPart}`, { responseType: 'text' }).pipe(map(passwords => passwords.split(/[\r\n]+/)), map(passwords => passwords.map((password) => {
|
|
39
|
+
const split = password.split(':');
|
|
40
|
+
return {
|
|
41
|
+
hash: split[0],
|
|
42
|
+
count: parseInt(split[1], 10),
|
|
43
|
+
};
|
|
44
|
+
})), map(passwords => passwords.find(password => password.hash === hash.lastPart)))), map(password => password && password.count >= this.pwnedPasswordMinimumOccurrenceForError
|
|
45
|
+
? { pwnedPasswordOccurrence: password.count }
|
|
46
|
+
: null));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
PasswordCheckerLibDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerLibDirective, deps: [{ token: i1.HttpClient }, { token: PasswordCheckerConfigValue, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
50
|
+
PasswordCheckerLibDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.0.2", type: PasswordCheckerLibDirective, selector: "[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]", inputs: { pwnedPasswordApi: "pwnedPasswordApi", pwnedPasswordMinimumOccurrenceForError: "pwnedPasswordMinimumOccurrenceForError", pwnedPasswordApiCallDebounceTime: "pwnedPasswordApiCallDebounceTime" }, providers: [
|
|
51
|
+
{
|
|
52
|
+
provide: NG_ASYNC_VALIDATORS,
|
|
53
|
+
useExisting: PasswordCheckerLibDirective,
|
|
54
|
+
multi: true,
|
|
55
|
+
},
|
|
56
|
+
], ngImport: i0 });
|
|
57
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerLibDirective, decorators: [{
|
|
58
|
+
type: Directive,
|
|
59
|
+
args: [{
|
|
60
|
+
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
61
|
+
selector: '[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]',
|
|
62
|
+
providers: [
|
|
63
|
+
{
|
|
64
|
+
provide: NG_ASYNC_VALIDATORS,
|
|
65
|
+
useExisting: PasswordCheckerLibDirective,
|
|
66
|
+
multi: true,
|
|
67
|
+
},
|
|
68
|
+
]
|
|
69
|
+
}]
|
|
70
|
+
}], ctorParameters: function () {
|
|
71
|
+
return [{ type: i1.HttpClient }, { type: undefined, decorators: [{
|
|
72
|
+
type: Optional
|
|
73
|
+
}, {
|
|
74
|
+
type: Inject,
|
|
75
|
+
args: [PasswordCheckerConfigValue]
|
|
76
|
+
}] }];
|
|
77
|
+
}, propDecorators: { pwnedPasswordApi: [{
|
|
78
|
+
type: Input
|
|
79
|
+
}], pwnedPasswordMinimumOccurrenceForError: [{
|
|
80
|
+
type: Input
|
|
81
|
+
}], pwnedPasswordApiCallDebounceTime: [{
|
|
82
|
+
type: Input
|
|
83
|
+
}] } });
|
|
84
|
+
|
|
85
|
+
class PasswordCheckerModule {
|
|
86
|
+
static forRoot(config = {}) {
|
|
87
|
+
return {
|
|
88
|
+
ngModule: PasswordCheckerModule,
|
|
89
|
+
providers: [
|
|
90
|
+
{
|
|
91
|
+
provide: PasswordCheckerConfigValue,
|
|
92
|
+
useValue: config,
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
PasswordCheckerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
99
|
+
PasswordCheckerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, declarations: [PasswordCheckerLibDirective], imports: [HttpClientModule], exports: [PasswordCheckerLibDirective] });
|
|
100
|
+
PasswordCheckerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, imports: [[HttpClientModule]] });
|
|
101
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, decorators: [{
|
|
102
|
+
type: NgModule,
|
|
103
|
+
args: [{
|
|
104
|
+
declarations: [PasswordCheckerLibDirective],
|
|
105
|
+
imports: [HttpClientModule],
|
|
106
|
+
exports: [PasswordCheckerLibDirective]
|
|
107
|
+
}]
|
|
108
|
+
}] });
|
|
109
|
+
|
|
110
|
+
/*
|
|
111
|
+
* Public API Surface of password-checker-lib
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Generated bundle index. Do not edit.
|
|
116
|
+
*/
|
|
117
|
+
|
|
118
|
+
export { PasswordCheckerLibDirective, PasswordCheckerModule };
|
|
119
|
+
//# sourceMappingURL=triangular-password-checker.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triangular-password-checker.mjs","sources":["../../../projects/password-checker-lib/src/lib/password-checker.config.ts","../../../projects/password-checker-lib/src/lib/password-checker-lib.directive.ts","../../../projects/password-checker-lib/src/lib/password-checker-lib.module.ts","../../../projects/password-checker-lib/src/public_api.ts","../../../projects/password-checker-lib/src/triangular-password-checker.ts"],"sourcesContent":["import {InjectionToken} from '@angular/core';\n\nexport type Partial<T> = {\n [P in keyof T]?: T[P];\n};\n\nexport interface PasswordCheckerConfig {\n pwnedPasswordApi: string;\n pwnedPasswordMinimumOccurrenceForError: number;\n pwnedPasswordApiCallDebounceTime: number;\n}\n\nexport const PasswordCheckerConfigValue = new InjectionToken<Partial<PasswordCheckerConfig>>('PASSWORD_CHECKER_CONFIG');\n","import { Observable, timer } from 'rxjs';\nimport { map, switchMap } from 'rxjs/operators';\nimport { AbstractControl, AsyncValidator, NG_ASYNC_VALIDATORS, ValidationErrors } from '@angular/forms';\nimport { Directive, Inject, Input, Optional } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport sha1 from 'crypto-js/sha1';\nimport { Partial, PasswordCheckerConfig, PasswordCheckerConfigValue } from './password-checker.config';\n\n@Directive({\n // eslint-disable-next-line @angular-eslint/directive-selector\n selector: '[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]',\n providers: [\n {\n provide: NG_ASYNC_VALIDATORS,\n useExisting: PasswordCheckerLibDirective,\n multi: true,\n },\n ]\n})\nexport class PasswordCheckerLibDirective implements AsyncValidator {\n private pwnedPasswordMinimumOccurrenceForErrorValue: number;\n\n @Input() pwnedPasswordApi: string;\n @Input() pwnedPasswordMinimumOccurrenceForError: number;\n @Input() pwnedPasswordApiCallDebounceTime: number;\n\n constructor(\n private http: HttpClient,\n @Optional() @Inject(PasswordCheckerConfigValue) config: Partial<PasswordCheckerConfig>,\n ) {\n\n if (!config) {\n // default initialization in constructor didn't work.\n // conflict with @Optional()?\n config = {};\n }\n\n this.pwnedPasswordApi =\n config.pwnedPasswordApi\n || 'https://api.pwnedpasswords.com/range/';\n this.pwnedPasswordMinimumOccurrenceForError =\n config.pwnedPasswordMinimumOccurrenceForError\n || 1;\n this.pwnedPasswordApiCallDebounceTime =\n config.pwnedPasswordApiCallDebounceTime\n || 400;\n }\n\n validate(control: AbstractControl): Observable<ValidationErrors|null> {\n const pw = ''.concat(control.value);\n\n return timer(this.pwnedPasswordApiCallDebounceTime).pipe(\n map(() => {\n const pwSha1 = sha1(pw).toString().toUpperCase();\n\n return {\n firstPart: pwSha1.substring(0, 5),\n lastPart: pwSha1.substring(5),\n };\n }),\n switchMap(\n (hash) => this.http.get(\n `${this.pwnedPasswordApi}${hash.firstPart}`, { responseType: 'text' }\n ).pipe(\n map(passwords => passwords.split(/[\\r\\n]+/)),\n map(passwords => passwords.map((password) => {\n const split = password.split(':');\n\n return {\n hash: split[0],\n count: parseInt(split[1], 10),\n };\n }\n )),\n map(passwords => passwords.find(password => password.hash === hash.lastPart)),\n ),\n ),\n map(password => password && password.count >= this.pwnedPasswordMinimumOccurrenceForError\n ? { pwnedPasswordOccurrence: password.count }\n : null),\n );\n }\n}\n","import { ModuleWithProviders, NgModule } from '@angular/core';\nimport { PasswordCheckerLibDirective } from './password-checker-lib.directive';\nimport { HttpClientModule } from '@angular/common/http';\nimport { Partial, PasswordCheckerConfig, PasswordCheckerConfigValue } from './password-checker.config';\n\n@NgModule({\n declarations: [PasswordCheckerLibDirective],\n imports: [HttpClientModule],\n exports: [PasswordCheckerLibDirective]\n})\nexport class PasswordCheckerModule {\n static forRoot(config: Partial<PasswordCheckerConfig> = {}): ModuleWithProviders<PasswordCheckerModule> {\n return {\n ngModule: PasswordCheckerModule,\n providers: [\n {\n provide: PasswordCheckerConfigValue,\n useValue: config,\n }\n ]\n };\n }\n}\n","/*\n * Public API Surface of password-checker-lib\n */\n\nexport * from './lib/password-checker-lib.directive';\nexport * from './lib/password-checker-lib.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { timer } from 'rxjs';
|
|
2
|
+
import { map, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { NG_ASYNC_VALIDATORS } from '@angular/forms';
|
|
4
|
+
import * as i0 from '@angular/core';
|
|
5
|
+
import { InjectionToken, Directive, Optional, Inject, Input, NgModule } from '@angular/core';
|
|
6
|
+
import sha1 from 'crypto-js/sha1';
|
|
7
|
+
import * as i1 from '@angular/common/http';
|
|
8
|
+
import { HttpClientModule } from '@angular/common/http';
|
|
9
|
+
|
|
10
|
+
const PasswordCheckerConfigValue = new InjectionToken('PASSWORD_CHECKER_CONFIG');
|
|
11
|
+
|
|
12
|
+
class PasswordCheckerLibDirective {
|
|
13
|
+
constructor(http, config) {
|
|
14
|
+
this.http = http;
|
|
15
|
+
if (!config) {
|
|
16
|
+
// default initialization in constructor didn't work.
|
|
17
|
+
// conflict with @Optional()?
|
|
18
|
+
config = {};
|
|
19
|
+
}
|
|
20
|
+
this.pwnedPasswordApi =
|
|
21
|
+
config.pwnedPasswordApi
|
|
22
|
+
|| 'https://api.pwnedpasswords.com/range/';
|
|
23
|
+
this.pwnedPasswordMinimumOccurrenceForError =
|
|
24
|
+
config.pwnedPasswordMinimumOccurrenceForError
|
|
25
|
+
|| 1;
|
|
26
|
+
this.pwnedPasswordApiCallDebounceTime =
|
|
27
|
+
config.pwnedPasswordApiCallDebounceTime
|
|
28
|
+
|| 400;
|
|
29
|
+
}
|
|
30
|
+
validate(control) {
|
|
31
|
+
const pw = ''.concat(control.value);
|
|
32
|
+
return timer(this.pwnedPasswordApiCallDebounceTime).pipe(map(() => {
|
|
33
|
+
const pwSha1 = sha1(pw).toString().toUpperCase();
|
|
34
|
+
return {
|
|
35
|
+
firstPart: pwSha1.substring(0, 5),
|
|
36
|
+
lastPart: pwSha1.substring(5),
|
|
37
|
+
};
|
|
38
|
+
}), switchMap((hash) => this.http.get(`${this.pwnedPasswordApi}${hash.firstPart}`, { responseType: 'text' }).pipe(map(passwords => passwords.split(/[\r\n]+/)), map(passwords => passwords.map((password) => {
|
|
39
|
+
const split = password.split(':');
|
|
40
|
+
return {
|
|
41
|
+
hash: split[0],
|
|
42
|
+
count: parseInt(split[1], 10),
|
|
43
|
+
};
|
|
44
|
+
})), map(passwords => passwords.find(password => password.hash === hash.lastPart)))), map(password => password && password.count >= this.pwnedPasswordMinimumOccurrenceForError
|
|
45
|
+
? { pwnedPasswordOccurrence: password.count }
|
|
46
|
+
: null));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
PasswordCheckerLibDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerLibDirective, deps: [{ token: i1.HttpClient }, { token: PasswordCheckerConfigValue, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
|
|
50
|
+
PasswordCheckerLibDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.0.2", type: PasswordCheckerLibDirective, selector: "[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]", inputs: { pwnedPasswordApi: "pwnedPasswordApi", pwnedPasswordMinimumOccurrenceForError: "pwnedPasswordMinimumOccurrenceForError", pwnedPasswordApiCallDebounceTime: "pwnedPasswordApiCallDebounceTime" }, providers: [
|
|
51
|
+
{
|
|
52
|
+
provide: NG_ASYNC_VALIDATORS,
|
|
53
|
+
useExisting: PasswordCheckerLibDirective,
|
|
54
|
+
multi: true,
|
|
55
|
+
},
|
|
56
|
+
], ngImport: i0 });
|
|
57
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerLibDirective, decorators: [{
|
|
58
|
+
type: Directive,
|
|
59
|
+
args: [{
|
|
60
|
+
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
61
|
+
selector: '[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]',
|
|
62
|
+
providers: [
|
|
63
|
+
{
|
|
64
|
+
provide: NG_ASYNC_VALIDATORS,
|
|
65
|
+
useExisting: PasswordCheckerLibDirective,
|
|
66
|
+
multi: true,
|
|
67
|
+
},
|
|
68
|
+
]
|
|
69
|
+
}]
|
|
70
|
+
}], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: undefined, decorators: [{
|
|
71
|
+
type: Optional
|
|
72
|
+
}, {
|
|
73
|
+
type: Inject,
|
|
74
|
+
args: [PasswordCheckerConfigValue]
|
|
75
|
+
}] }]; }, propDecorators: { pwnedPasswordApi: [{
|
|
76
|
+
type: Input
|
|
77
|
+
}], pwnedPasswordMinimumOccurrenceForError: [{
|
|
78
|
+
type: Input
|
|
79
|
+
}], pwnedPasswordApiCallDebounceTime: [{
|
|
80
|
+
type: Input
|
|
81
|
+
}] } });
|
|
82
|
+
|
|
83
|
+
class PasswordCheckerModule {
|
|
84
|
+
static forRoot(config = {}) {
|
|
85
|
+
return {
|
|
86
|
+
ngModule: PasswordCheckerModule,
|
|
87
|
+
providers: [
|
|
88
|
+
{
|
|
89
|
+
provide: PasswordCheckerConfigValue,
|
|
90
|
+
useValue: config,
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
PasswordCheckerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
97
|
+
PasswordCheckerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, declarations: [PasswordCheckerLibDirective], imports: [HttpClientModule], exports: [PasswordCheckerLibDirective] });
|
|
98
|
+
PasswordCheckerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, imports: [[HttpClientModule]] });
|
|
99
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: PasswordCheckerModule, decorators: [{
|
|
100
|
+
type: NgModule,
|
|
101
|
+
args: [{
|
|
102
|
+
declarations: [PasswordCheckerLibDirective],
|
|
103
|
+
imports: [HttpClientModule],
|
|
104
|
+
exports: [PasswordCheckerLibDirective]
|
|
105
|
+
}]
|
|
106
|
+
}] });
|
|
107
|
+
|
|
108
|
+
/*
|
|
109
|
+
* Public API Surface of password-checker-lib
|
|
110
|
+
*/
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Generated bundle index. Do not edit.
|
|
114
|
+
*/
|
|
115
|
+
|
|
116
|
+
export { PasswordCheckerLibDirective, PasswordCheckerModule };
|
|
117
|
+
//# sourceMappingURL=triangular-password-checker.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triangular-password-checker.mjs","sources":["../../../projects/password-checker-lib/src/lib/password-checker.config.ts","../../../projects/password-checker-lib/src/lib/password-checker-lib.directive.ts","../../../projects/password-checker-lib/src/lib/password-checker-lib.module.ts","../../../projects/password-checker-lib/src/public_api.ts","../../../projects/password-checker-lib/src/triangular-password-checker.ts"],"sourcesContent":["import {InjectionToken} from '@angular/core';\n\nexport type Partial<T> = {\n [P in keyof T]?: T[P];\n};\n\nexport interface PasswordCheckerConfig {\n pwnedPasswordApi: string;\n pwnedPasswordMinimumOccurrenceForError: number;\n pwnedPasswordApiCallDebounceTime: number;\n}\n\nexport const PasswordCheckerConfigValue = new InjectionToken<Partial<PasswordCheckerConfig>>('PASSWORD_CHECKER_CONFIG');\n","import { Observable, timer } from 'rxjs';\nimport { map, switchMap } from 'rxjs/operators';\nimport { AbstractControl, AsyncValidator, NG_ASYNC_VALIDATORS, ValidationErrors } from '@angular/forms';\nimport { Directive, Inject, Input, Optional } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport sha1 from 'crypto-js/sha1';\nimport { Partial, PasswordCheckerConfig, PasswordCheckerConfigValue } from './password-checker.config';\n\n@Directive({\n // eslint-disable-next-line @angular-eslint/directive-selector\n selector: '[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]',\n providers: [\n {\n provide: NG_ASYNC_VALIDATORS,\n useExisting: PasswordCheckerLibDirective,\n multi: true,\n },\n ]\n})\nexport class PasswordCheckerLibDirective implements AsyncValidator {\n private pwnedPasswordMinimumOccurrenceForErrorValue: number;\n\n @Input() pwnedPasswordApi: string;\n @Input() pwnedPasswordMinimumOccurrenceForError: number;\n @Input() pwnedPasswordApiCallDebounceTime: number;\n\n constructor(\n private http: HttpClient,\n @Optional() @Inject(PasswordCheckerConfigValue) config: Partial<PasswordCheckerConfig>,\n ) {\n\n if (!config) {\n // default initialization in constructor didn't work.\n // conflict with @Optional()?\n config = {};\n }\n\n this.pwnedPasswordApi =\n config.pwnedPasswordApi\n || 'https://api.pwnedpasswords.com/range/';\n this.pwnedPasswordMinimumOccurrenceForError =\n config.pwnedPasswordMinimumOccurrenceForError\n || 1;\n this.pwnedPasswordApiCallDebounceTime =\n config.pwnedPasswordApiCallDebounceTime\n || 400;\n }\n\n validate(control: AbstractControl): Observable<ValidationErrors|null> {\n const pw = ''.concat(control.value);\n\n return timer(this.pwnedPasswordApiCallDebounceTime).pipe(\n map(() => {\n const pwSha1 = sha1(pw).toString().toUpperCase();\n\n return {\n firstPart: pwSha1.substring(0, 5),\n lastPart: pwSha1.substring(5),\n };\n }),\n switchMap(\n (hash) => this.http.get(\n `${this.pwnedPasswordApi}${hash.firstPart}`, { responseType: 'text' }\n ).pipe(\n map(passwords => passwords.split(/[\\r\\n]+/)),\n map(passwords => passwords.map((password) => {\n const split = password.split(':');\n\n return {\n hash: split[0],\n count: parseInt(split[1], 10),\n };\n }\n )),\n map(passwords => passwords.find(password => password.hash === hash.lastPart)),\n ),\n ),\n map(password => password && password.count >= this.pwnedPasswordMinimumOccurrenceForError\n ? { pwnedPasswordOccurrence: password.count }\n : null),\n );\n }\n}\n","import { ModuleWithProviders, NgModule } from '@angular/core';\nimport { PasswordCheckerLibDirective } from './password-checker-lib.directive';\nimport { HttpClientModule } from '@angular/common/http';\nimport { Partial, PasswordCheckerConfig, PasswordCheckerConfigValue } from './password-checker.config';\n\n@NgModule({\n declarations: [PasswordCheckerLibDirective],\n imports: [HttpClientModule],\n exports: [PasswordCheckerLibDirective]\n})\nexport class PasswordCheckerModule {\n static forRoot(config: Partial<PasswordCheckerConfig> = {}): ModuleWithProviders<PasswordCheckerModule> {\n return {\n ngModule: PasswordCheckerModule,\n providers: [\n {\n provide: PasswordCheckerConfigValue,\n useValue: config,\n }\n ]\n };\n }\n}\n","/*\n * Public API Surface of password-checker-lib\n */\n\nexport * from './lib/password-checker-lib.directive';\nexport * from './lib/password-checker-lib.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { Observable } from 'rxjs';
|
|
|
2
2
|
import { AbstractControl, AsyncValidator, ValidationErrors } from '@angular/forms';
|
|
3
3
|
import { HttpClient } from '@angular/common/http';
|
|
4
4
|
import { Partial, PasswordCheckerConfig } from './password-checker.config';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
5
6
|
export declare class PasswordCheckerLibDirective implements AsyncValidator {
|
|
6
7
|
private http;
|
|
7
8
|
private pwnedPasswordMinimumOccurrenceForErrorValue;
|
|
@@ -10,4 +11,6 @@ export declare class PasswordCheckerLibDirective implements AsyncValidator {
|
|
|
10
11
|
pwnedPasswordApiCallDebounceTime: number;
|
|
11
12
|
constructor(http: HttpClient, config: Partial<PasswordCheckerConfig>);
|
|
12
13
|
validate(control: AbstractControl): Observable<ValidationErrors | null>;
|
|
14
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<PasswordCheckerLibDirective, [null, { optional: true; }]>;
|
|
15
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<PasswordCheckerLibDirective, "[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]", never, { "pwnedPasswordApi": "pwnedPasswordApi"; "pwnedPasswordMinimumOccurrenceForError": "pwnedPasswordMinimumOccurrenceForError"; "pwnedPasswordApiCallDebounceTime": "pwnedPasswordApiCallDebounceTime"; }, {}, never>;
|
|
13
16
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { ModuleWithProviders } from '@angular/core';
|
|
2
2
|
import { Partial, PasswordCheckerConfig } from './password-checker.config';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "./password-checker-lib.directive";
|
|
5
|
+
import * as i2 from "@angular/common/http";
|
|
3
6
|
export declare class PasswordCheckerModule {
|
|
4
7
|
static forRoot(config?: Partial<PasswordCheckerConfig>): ModuleWithProviders<PasswordCheckerModule>;
|
|
8
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<PasswordCheckerModule, never>;
|
|
9
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<PasswordCheckerModule, [typeof i1.PasswordCheckerLibDirective], [typeof i2.HttpClientModule], [typeof i1.PasswordCheckerLibDirective]>;
|
|
10
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<PasswordCheckerModule>;
|
|
5
11
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@triangular/password-checker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.1",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@angular/common": "^
|
|
6
|
-
"@angular/core": "^
|
|
5
|
+
"@angular/common": "^13.0.0",
|
|
6
|
+
"@angular/core": "^13.0.0",
|
|
7
7
|
"crypto-js": "^3.3.0"
|
|
8
8
|
},
|
|
9
9
|
"homepage": "https://password.akehir.com",
|
|
@@ -24,12 +24,24 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"tslib": "^2.0.0"
|
|
26
26
|
},
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"fesm2015": "fesm2015/triangular-password-checker.
|
|
27
|
+
"module": "fesm2015/triangular-password-checker.mjs",
|
|
28
|
+
"es2020": "fesm2020/triangular-password-checker.mjs",
|
|
29
|
+
"esm2020": "esm2020/triangular-password-checker.mjs",
|
|
30
|
+
"fesm2020": "fesm2020/triangular-password-checker.mjs",
|
|
31
|
+
"fesm2015": "fesm2015/triangular-password-checker.mjs",
|
|
32
32
|
"typings": "triangular-password-checker.d.ts",
|
|
33
|
-
"
|
|
33
|
+
"exports": {
|
|
34
|
+
"./package.json": {
|
|
35
|
+
"default": "./package.json"
|
|
36
|
+
},
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./triangular-password-checker.d.ts",
|
|
39
|
+
"esm2020": "./esm2020/triangular-password-checker.mjs",
|
|
40
|
+
"es2020": "./fesm2020/triangular-password-checker.mjs",
|
|
41
|
+
"es2015": "./fesm2015/triangular-password-checker.mjs",
|
|
42
|
+
"node": "./fesm2015/triangular-password-checker.mjs",
|
|
43
|
+
"default": "./fesm2020/triangular-password-checker.mjs"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
34
46
|
"sideEffects": false
|
|
35
|
-
}
|
|
47
|
+
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('rxjs'), require('rxjs/operators'), require('@angular/forms'), require('@angular/core'), require('@angular/common/http'), require('crypto-js/sha1')) :
|
|
3
|
-
typeof define === 'function' && define.amd ? define('@triangular/password-checker', ['exports', 'rxjs', 'rxjs/operators', '@angular/forms', '@angular/core', '@angular/common/http', 'crypto-js/sha1'], factory) :
|
|
4
|
-
(global = global || self, factory((global.triangular = global.triangular || {}, global.triangular['password-checker'] = {}), global.rxjs, global.rxjs.operators, global.ng.forms, global.ng.core, global.ng.common.http, global.sha1));
|
|
5
|
-
}(this, (function (exports, rxjs, operators, forms, core, http, sha1) { 'use strict';
|
|
6
|
-
|
|
7
|
-
sha1 = sha1 && Object.prototype.hasOwnProperty.call(sha1, 'default') ? sha1['default'] : sha1;
|
|
8
|
-
|
|
9
|
-
var PasswordCheckerConfigValue = new core.InjectionToken('PASSWORD_CHECKER_CONFIG');
|
|
10
|
-
|
|
11
|
-
var PasswordCheckerLibDirective = /** @class */ (function () {
|
|
12
|
-
function PasswordCheckerLibDirective(http, config) {
|
|
13
|
-
this.http = http;
|
|
14
|
-
if (!config) {
|
|
15
|
-
// default initialization in constructor didn't work.
|
|
16
|
-
// conflict with @Optional()?
|
|
17
|
-
config = {};
|
|
18
|
-
}
|
|
19
|
-
this.pwnedPasswordApi =
|
|
20
|
-
config.pwnedPasswordApi
|
|
21
|
-
|| 'https://api.pwnedpasswords.com/range/';
|
|
22
|
-
this.pwnedPasswordMinimumOccurrenceForError =
|
|
23
|
-
config.pwnedPasswordMinimumOccurrenceForError
|
|
24
|
-
|| 1;
|
|
25
|
-
this.pwnedPasswordApiCallDebounceTime =
|
|
26
|
-
config.pwnedPasswordApiCallDebounceTime
|
|
27
|
-
|| 400;
|
|
28
|
-
}
|
|
29
|
-
PasswordCheckerLibDirective.prototype.validate = function (control) {
|
|
30
|
-
var _this = this;
|
|
31
|
-
var pw = ''.concat(control.value);
|
|
32
|
-
return rxjs.timer(this.pwnedPasswordApiCallDebounceTime).pipe(operators.map(function () {
|
|
33
|
-
var pwSha1 = sha1(pw).toString().toUpperCase();
|
|
34
|
-
return {
|
|
35
|
-
firstPart: pwSha1.substring(0, 5),
|
|
36
|
-
lastPart: pwSha1.substring(5),
|
|
37
|
-
};
|
|
38
|
-
}), operators.switchMap(function (hash) { return _this.http.get("" + _this.pwnedPasswordApi + hash.firstPart, { responseType: 'text' }).pipe(operators.map(function (passwords) { return passwords.split(/[\r\n]+/); }), operators.map(function (passwords) { return passwords.map(function (password) {
|
|
39
|
-
var split = password.split(':');
|
|
40
|
-
return {
|
|
41
|
-
hash: split[0],
|
|
42
|
-
count: parseInt(split[1], 10),
|
|
43
|
-
};
|
|
44
|
-
}); }), operators.map(function (passwords) { return passwords.find(function (password) { return password.hash === hash.lastPart; }); })); }), operators.map(function (password) { return password && password.count >= _this.pwnedPasswordMinimumOccurrenceForError
|
|
45
|
-
? { pwnedPasswordOccurrence: password.count }
|
|
46
|
-
: null; }));
|
|
47
|
-
};
|
|
48
|
-
return PasswordCheckerLibDirective;
|
|
49
|
-
}());
|
|
50
|
-
PasswordCheckerLibDirective.decorators = [
|
|
51
|
-
{ type: core.Directive, args: [{
|
|
52
|
-
// tslint:disable-next-line directive-selector
|
|
53
|
-
selector: '[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]',
|
|
54
|
-
providers: [
|
|
55
|
-
{
|
|
56
|
-
provide: forms.NG_ASYNC_VALIDATORS,
|
|
57
|
-
useExisting: PasswordCheckerLibDirective,
|
|
58
|
-
multi: true,
|
|
59
|
-
},
|
|
60
|
-
]
|
|
61
|
-
},] }
|
|
62
|
-
];
|
|
63
|
-
PasswordCheckerLibDirective.ctorParameters = function () { return [
|
|
64
|
-
{ type: http.HttpClient },
|
|
65
|
-
{ type: undefined, decorators: [{ type: core.Optional }, { type: core.Inject, args: [PasswordCheckerConfigValue,] }] }
|
|
66
|
-
]; };
|
|
67
|
-
PasswordCheckerLibDirective.propDecorators = {
|
|
68
|
-
pwnedPasswordApi: [{ type: core.Input }],
|
|
69
|
-
pwnedPasswordMinimumOccurrenceForError: [{ type: core.Input }],
|
|
70
|
-
pwnedPasswordApiCallDebounceTime: [{ type: core.Input }]
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
var PasswordCheckerModule = /** @class */ (function () {
|
|
74
|
-
function PasswordCheckerModule() {
|
|
75
|
-
}
|
|
76
|
-
PasswordCheckerModule.forRoot = function (config) {
|
|
77
|
-
if (config === void 0) { config = {}; }
|
|
78
|
-
return {
|
|
79
|
-
ngModule: PasswordCheckerModule,
|
|
80
|
-
providers: [
|
|
81
|
-
{
|
|
82
|
-
provide: PasswordCheckerConfigValue,
|
|
83
|
-
useValue: config,
|
|
84
|
-
}
|
|
85
|
-
]
|
|
86
|
-
};
|
|
87
|
-
};
|
|
88
|
-
return PasswordCheckerModule;
|
|
89
|
-
}());
|
|
90
|
-
PasswordCheckerModule.decorators = [
|
|
91
|
-
{ type: core.NgModule, args: [{
|
|
92
|
-
declarations: [PasswordCheckerLibDirective],
|
|
93
|
-
imports: [http.HttpClientModule],
|
|
94
|
-
exports: [PasswordCheckerLibDirective]
|
|
95
|
-
},] }
|
|
96
|
-
];
|
|
97
|
-
|
|
98
|
-
/*
|
|
99
|
-
* Public API Surface of password-checker-lib
|
|
100
|
-
*/
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Generated bundle index. Do not edit.
|
|
104
|
-
*/
|
|
105
|
-
|
|
106
|
-
exports.PasswordCheckerLibDirective = PasswordCheckerLibDirective;
|
|
107
|
-
exports.PasswordCheckerModule = PasswordCheckerModule;
|
|
108
|
-
exports.ɵb = PasswordCheckerConfigValue;
|
|
109
|
-
|
|
110
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
111
|
-
|
|
112
|
-
})));
|
|
113
|
-
//# sourceMappingURL=triangular-password-checker.umd.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"triangular-password-checker.umd.js","sources":["../../../projects/password-checker-lib/src/lib/password-checker.config.ts","../../../projects/password-checker-lib/src/lib/password-checker-lib.directive.ts","../../../projects/password-checker-lib/src/lib/password-checker-lib.module.ts","../../../projects/password-checker-lib/src/public_api.ts","../../../projects/password-checker-lib/src/triangular-password-checker.ts"],"sourcesContent":["import {InjectionToken} from '@angular/core';\n\nexport type Partial<T> = {\n [P in keyof T]?: T[P];\n};\n\nexport interface PasswordCheckerConfig {\n pwnedPasswordApi: string;\n pwnedPasswordMinimumOccurrenceForError: number;\n pwnedPasswordApiCallDebounceTime: number;\n}\n\nexport const PasswordCheckerConfigValue = new InjectionToken<Partial<PasswordCheckerConfig>>('PASSWORD_CHECKER_CONFIG');\n","import { Observable, timer } from 'rxjs';\nimport { map, switchMap } from 'rxjs/operators';\nimport { AbstractControl, AsyncValidator, NG_ASYNC_VALIDATORS, ValidationErrors } from '@angular/forms';\nimport { Directive, Inject, Input, Optional } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport sha1 from 'crypto-js/sha1';\nimport { Partial, PasswordCheckerConfig, PasswordCheckerConfigValue } from './password-checker.config';\n\n@Directive({\n // tslint:disable-next-line directive-selector\n selector: '[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]',\n providers: [\n {\n provide: NG_ASYNC_VALIDATORS,\n useExisting: PasswordCheckerLibDirective,\n multi: true,\n },\n ]\n})\nexport class PasswordCheckerLibDirective implements AsyncValidator {\n private pwnedPasswordMinimumOccurrenceForErrorValue: number;\n\n @Input() pwnedPasswordApi: string;\n @Input() pwnedPasswordMinimumOccurrenceForError: number;\n @Input() pwnedPasswordApiCallDebounceTime: number;\n\n constructor(\n private http: HttpClient,\n @Optional() @Inject(PasswordCheckerConfigValue) config: Partial<PasswordCheckerConfig>,\n ) {\n\n if (!config) {\n // default initialization in constructor didn't work.\n // conflict with @Optional()?\n config = {};\n }\n\n this.pwnedPasswordApi =\n config.pwnedPasswordApi\n || 'https://api.pwnedpasswords.com/range/';\n this.pwnedPasswordMinimumOccurrenceForError =\n config.pwnedPasswordMinimumOccurrenceForError\n || 1;\n this.pwnedPasswordApiCallDebounceTime =\n config.pwnedPasswordApiCallDebounceTime\n || 400;\n }\n\n validate(control: AbstractControl): Observable<ValidationErrors|null> {\n const pw = ''.concat(control.value);\n\n return timer(this.pwnedPasswordApiCallDebounceTime).pipe(\n map(() => {\n const pwSha1 = sha1(pw).toString().toUpperCase();\n\n return {\n firstPart: pwSha1.substring(0, 5),\n lastPart: pwSha1.substring(5),\n };\n }),\n switchMap(\n (hash) => this.http.get(\n `${this.pwnedPasswordApi}${hash.firstPart}`, { responseType: 'text' }\n ).pipe(\n map(passwords => passwords.split(/[\\r\\n]+/)),\n map(passwords => passwords.map((password) => {\n const split = password.split(':');\n\n return {\n hash: split[0],\n count: parseInt(split[1], 10),\n };\n }\n )),\n map(passwords => passwords.find(password => password.hash === hash.lastPart)),\n ),\n ),\n map(password => password && password.count >= this.pwnedPasswordMinimumOccurrenceForError\n ? { pwnedPasswordOccurrence: password.count }\n : null),\n );\n }\n}\n","import { ModuleWithProviders, NgModule } from '@angular/core';\nimport { PasswordCheckerLibDirective } from './password-checker-lib.directive';\nimport { HttpClientModule } from '@angular/common/http';\nimport { Partial, PasswordCheckerConfig, PasswordCheckerConfigValue } from './password-checker.config';\n\n@NgModule({\n declarations: [PasswordCheckerLibDirective],\n imports: [HttpClientModule],\n exports: [PasswordCheckerLibDirective]\n})\nexport class PasswordCheckerModule {\n static forRoot(config: Partial<PasswordCheckerConfig> = {}): ModuleWithProviders<PasswordCheckerModule> {\n return {\n ngModule: PasswordCheckerModule,\n providers: [\n {\n provide: PasswordCheckerConfigValue,\n useValue: config,\n }\n ]\n };\n }\n}\n","/*\n * Public API Surface of password-checker-lib\n */\n\nexport * from './lib/password-checker-lib.directive';\nexport * from './lib/password-checker-lib.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n\nexport {Partial as ɵa,PasswordCheckerConfigValue as ɵb} from './lib/password-checker.config';"],"names":["InjectionToken","timer","map","switchMap","Directive","NG_ASYNC_VALIDATORS","HttpClient","Optional","Inject","Input","NgModule","HttpClientModule"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
!function(r,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("rxjs"),require("rxjs/operators"),require("@angular/forms"),require("@angular/core"),require("@angular/common/http"),require("crypto-js/sha1")):"function"==typeof define&&define.amd?define("@triangular/password-checker",["exports","rxjs","rxjs/operators","@angular/forms","@angular/core","@angular/common/http","crypto-js/sha1"],e):e(((r=r||self).triangular=r.triangular||{},r.triangular["password-checker"]={}),r.rxjs,r.rxjs.operators,r.ng.forms,r.ng.core,r.ng.common.http,r.sha1)}(this,(function(r,e,t,o,n,s,a){"use strict";a=a&&Object.prototype.hasOwnProperty.call(a,"default")?a.default:a;var i=new n.InjectionToken("PASSWORD_CHECKER_CONFIG"),p=function(){function r(r,e){this.http=r,e||(e={}),this.pwnedPasswordApi=e.pwnedPasswordApi||"https://api.pwnedpasswords.com/range/",this.pwnedPasswordMinimumOccurrenceForError=e.pwnedPasswordMinimumOccurrenceForError||1,this.pwnedPasswordApiCallDebounceTime=e.pwnedPasswordApiCallDebounceTime||400}return r.prototype.validate=function(r){var o=this,n="".concat(r.value);return e.timer(this.pwnedPasswordApiCallDebounceTime).pipe(t.map((function(){var r=a(n).toString().toUpperCase();return{firstPart:r.substring(0,5),lastPart:r.substring(5)}})),t.switchMap((function(r){return o.http.get(""+o.pwnedPasswordApi+r.firstPart,{responseType:"text"}).pipe(t.map((function(r){return r.split(/[\r\n]+/)})),t.map((function(r){return r.map((function(r){var e=r.split(":");return{hash:e[0],count:parseInt(e[1],10)}}))})),t.map((function(e){return e.find((function(e){return e.hash===r.lastPart}))})))})),t.map((function(r){return r&&r.count>=o.pwnedPasswordMinimumOccurrenceForError?{pwnedPasswordOccurrence:r.count}:null})))},r}();p.decorators=[{type:n.Directive,args:[{selector:"[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]",providers:[{provide:o.NG_ASYNC_VALIDATORS,useExisting:p,multi:!0}]}]}],p.ctorParameters=function(){return[{type:s.HttpClient},{type:void 0,decorators:[{type:n.Optional},{type:n.Inject,args:[i]}]}]},p.propDecorators={pwnedPasswordApi:[{type:n.Input}],pwnedPasswordMinimumOccurrenceForError:[{type:n.Input}],pwnedPasswordApiCallDebounceTime:[{type:n.Input}]};var u=function(){function r(){}return r.forRoot=function(e){return void 0===e&&(e={}),{ngModule:r,providers:[{provide:i,useValue:e}]}},r}();u.decorators=[{type:n.NgModule,args:[{declarations:[p],imports:[s.HttpClientModule],exports:[p]}]}],r.PasswordCheckerLibDirective=p,r.PasswordCheckerModule=u,r.ɵb=i,Object.defineProperty(r,"__esModule",{value:!0})}));
|
|
2
|
-
//# sourceMappingURL=triangular-password-checker.umd.min.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../projects/password-checker-lib/src/lib/password-checker.config.ts","../../../projects/password-checker-lib/src/lib/password-checker-lib.directive.ts","../../../projects/password-checker-lib/src/lib/password-checker-lib.module.ts"],"names":["PasswordCheckerConfigValue","InjectionToken","PasswordCheckerLibDirective","http","config","this","pwnedPasswordApi","pwnedPasswordMinimumOccurrenceForError","pwnedPasswordApiCallDebounceTime","prototype","validate","control","_this","pw","concat","value","timer","pipe","map","pwSha1","sha1","toString","toUpperCase","firstPart","substring","lastPart","switchMap","hash","get","responseType","passwords","split","password","count","parseInt","find","pwnedPasswordOccurrence","Directive","args","selector","providers","provide","NG_ASYNC_VALIDATORS","useExisting","multi","HttpClient","Optional","type","Inject","Input","PasswordCheckerModule","forRoot","ngModule","useValue","NgModule","declarations","imports","HttpClientModule","exports"],"mappings":"2qBAYaA,EAA6B,IAAIC,EAAAA,eAA+C,wCCc3F,SAAAC,EACUC,EACwCC,GADxCC,KAAAF,KAAAA,EAIHC,IAGHA,EAAS,IAGXC,KAAKC,iBACHF,EAAOE,kBACJ,wCACLD,KAAKE,uCACHH,EAAOG,wCACJ,EACLF,KAAKG,iCACHJ,EAAOI,kCACJ,WAGPN,EAAAO,UAAAC,SAAA,SAASC,GAAT,IAAAC,EAAAP,KACQQ,EAAK,GAAGC,OAAOH,EAAQI,OAE7B,OAAOC,EAAAA,MAAMX,KAAKG,kCAAkCS,KAClDC,EAAAA,KAAI,WACF,IAAMC,EAASC,EAAKP,GAAIQ,WAAWC,cAEnC,MAAO,CACLC,UAAWJ,EAAOK,UAAU,EAAG,GAC/BC,SAAUN,EAAOK,UAAU,OAG/BE,EAAAA,WACE,SAACC,GAAS,OAAAf,EAAKT,KAAKyB,IAClB,GAAGhB,EAAKN,iBAAmBqB,EAAKJ,UAAc,CAAEM,aAAc,SAC5DZ,KACFC,EAAAA,KAAI,SAAAY,GAAa,OAAAA,EAAUC,MAAM,cACjCb,EAAAA,KAAI,SAAAY,GAAa,OAAAA,EAAUZ,KAAI,SAACc,GAC5B,IAAMD,EAASC,EAASD,MAAM,KAE9B,MAAO,CACLJ,KAAMI,EAAM,GACZE,MAAOC,SAASH,EAAM,GAAI,WAIhCb,EAAAA,KAAI,SAAAY,GAAa,OAAAA,EAAUK,MAAK,SAAAH,GAAY,OAAAA,EAASL,OAASA,EAAKF,mBAGvEP,EAAAA,KAAI,SAAAc,GAAY,OAAAA,GAAYA,EAASC,OAASrB,EAAKL,uCAC/C,CAAE6B,wBAAyBJ,EAASC,OACpC,mCAvETI,EAAAA,UAASC,KAAA,CAAC,CAETC,SAAU,qHACVC,UAAW,CACL,CACEC,QAASC,EAAAA,oBACTC,YAAazC,EACb0C,OAAO,iDAXRC,EAAAA,2CAwBJC,EAAAA,UAAQ,CAAAC,KAAIC,EAAAA,OAAMV,KAAA,CAACtC,kDANrBiD,EAAAA,sDACAA,EAAAA,gDACAA,EAAAA,0BCdH,SAAAC,YACSA,EAAAC,QAAP,SAAe/C,GACb,YADa,IAAAA,IAAAA,EAAA,IACN,CACLgD,SAAUF,EACVV,UAAW,CACT,CACEC,QAASzC,EACTqD,SAAUjD,+BAZnBkD,EAAAA,SAAQhB,KAAA,CAAC,CACRiB,aAAc,CAACrD,GACfsD,QAAS,CAACC,EAAAA,kBACVC,QAAS,CAACxD","sourcesContent":["import {InjectionToken} from '@angular/core';\n\nexport type Partial<T> = {\n [P in keyof T]?: T[P];\n};\n\nexport interface PasswordCheckerConfig {\n pwnedPasswordApi: string;\n pwnedPasswordMinimumOccurrenceForError: number;\n pwnedPasswordApiCallDebounceTime: number;\n}\n\nexport const PasswordCheckerConfigValue = new InjectionToken<Partial<PasswordCheckerConfig>>('PASSWORD_CHECKER_CONFIG');\n","import { Observable, timer } from 'rxjs';\nimport { map, switchMap } from 'rxjs/operators';\nimport { AbstractControl, AsyncValidator, NG_ASYNC_VALIDATORS, ValidationErrors } from '@angular/forms';\nimport { Directive, Inject, Input, Optional } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport sha1 from 'crypto-js/sha1';\nimport { Partial, PasswordCheckerConfig, PasswordCheckerConfigValue } from './password-checker.config';\n\n@Directive({\n // tslint:disable-next-line directive-selector\n selector: '[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]',\n providers: [\n {\n provide: NG_ASYNC_VALIDATORS,\n useExisting: PasswordCheckerLibDirective,\n multi: true,\n },\n ]\n})\nexport class PasswordCheckerLibDirective implements AsyncValidator {\n private pwnedPasswordMinimumOccurrenceForErrorValue: number;\n\n @Input() pwnedPasswordApi: string;\n @Input() pwnedPasswordMinimumOccurrenceForError: number;\n @Input() pwnedPasswordApiCallDebounceTime: number;\n\n constructor(\n private http: HttpClient,\n @Optional() @Inject(PasswordCheckerConfigValue) config: Partial<PasswordCheckerConfig>,\n ) {\n\n if (!config) {\n // default initialization in constructor didn't work.\n // conflict with @Optional()?\n config = {};\n }\n\n this.pwnedPasswordApi =\n config.pwnedPasswordApi\n || 'https://api.pwnedpasswords.com/range/';\n this.pwnedPasswordMinimumOccurrenceForError =\n config.pwnedPasswordMinimumOccurrenceForError\n || 1;\n this.pwnedPasswordApiCallDebounceTime =\n config.pwnedPasswordApiCallDebounceTime\n || 400;\n }\n\n validate(control: AbstractControl): Observable<ValidationErrors|null> {\n const pw = ''.concat(control.value);\n\n return timer(this.pwnedPasswordApiCallDebounceTime).pipe(\n map(() => {\n const pwSha1 = sha1(pw).toString().toUpperCase();\n\n return {\n firstPart: pwSha1.substring(0, 5),\n lastPart: pwSha1.substring(5),\n };\n }),\n switchMap(\n (hash) => this.http.get(\n `${this.pwnedPasswordApi}${hash.firstPart}`, { responseType: 'text' }\n ).pipe(\n map(passwords => passwords.split(/[\\r\\n]+/)),\n map(passwords => passwords.map((password) => {\n const split = password.split(':');\n\n return {\n hash: split[0],\n count: parseInt(split[1], 10),\n };\n }\n )),\n map(passwords => passwords.find(password => password.hash === hash.lastPart)),\n ),\n ),\n map(password => password && password.count >= this.pwnedPasswordMinimumOccurrenceForError\n ? { pwnedPasswordOccurrence: password.count }\n : null),\n );\n }\n}\n","import { ModuleWithProviders, NgModule } from '@angular/core';\nimport { PasswordCheckerLibDirective } from './password-checker-lib.directive';\nimport { HttpClientModule } from '@angular/common/http';\nimport { Partial, PasswordCheckerConfig, PasswordCheckerConfigValue } from './password-checker.config';\n\n@NgModule({\n declarations: [PasswordCheckerLibDirective],\n imports: [HttpClientModule],\n exports: [PasswordCheckerLibDirective]\n})\nexport class PasswordCheckerModule {\n static forRoot(config: Partial<PasswordCheckerConfig> = {}): ModuleWithProviders<PasswordCheckerModule> {\n return {\n ngModule: PasswordCheckerModule,\n providers: [\n {\n provide: PasswordCheckerConfigValue,\n useValue: config,\n }\n ]\n };\n }\n}\n"]}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { timer } from 'rxjs';
|
|
2
|
-
import { map, switchMap } from 'rxjs/operators';
|
|
3
|
-
import { NG_ASYNC_VALIDATORS } from '@angular/forms';
|
|
4
|
-
import { Directive, Inject, Input, Optional } from '@angular/core';
|
|
5
|
-
import { HttpClient } from '@angular/common/http';
|
|
6
|
-
import sha1 from 'crypto-js/sha1';
|
|
7
|
-
import { PasswordCheckerConfigValue } from './password-checker.config';
|
|
8
|
-
export class PasswordCheckerLibDirective {
|
|
9
|
-
constructor(http, config) {
|
|
10
|
-
this.http = http;
|
|
11
|
-
if (!config) {
|
|
12
|
-
// default initialization in constructor didn't work.
|
|
13
|
-
// conflict with @Optional()?
|
|
14
|
-
config = {};
|
|
15
|
-
}
|
|
16
|
-
this.pwnedPasswordApi =
|
|
17
|
-
config.pwnedPasswordApi
|
|
18
|
-
|| 'https://api.pwnedpasswords.com/range/';
|
|
19
|
-
this.pwnedPasswordMinimumOccurrenceForError =
|
|
20
|
-
config.pwnedPasswordMinimumOccurrenceForError
|
|
21
|
-
|| 1;
|
|
22
|
-
this.pwnedPasswordApiCallDebounceTime =
|
|
23
|
-
config.pwnedPasswordApiCallDebounceTime
|
|
24
|
-
|| 400;
|
|
25
|
-
}
|
|
26
|
-
validate(control) {
|
|
27
|
-
const pw = ''.concat(control.value);
|
|
28
|
-
return timer(this.pwnedPasswordApiCallDebounceTime).pipe(map(() => {
|
|
29
|
-
const pwSha1 = sha1(pw).toString().toUpperCase();
|
|
30
|
-
return {
|
|
31
|
-
firstPart: pwSha1.substring(0, 5),
|
|
32
|
-
lastPart: pwSha1.substring(5),
|
|
33
|
-
};
|
|
34
|
-
}), switchMap((hash) => this.http.get(`${this.pwnedPasswordApi}${hash.firstPart}`, { responseType: 'text' }).pipe(map(passwords => passwords.split(/[\r\n]+/)), map(passwords => passwords.map((password) => {
|
|
35
|
-
const split = password.split(':');
|
|
36
|
-
return {
|
|
37
|
-
hash: split[0],
|
|
38
|
-
count: parseInt(split[1], 10),
|
|
39
|
-
};
|
|
40
|
-
})), map(passwords => passwords.find(password => password.hash === hash.lastPart)))), map(password => password && password.count >= this.pwnedPasswordMinimumOccurrenceForError
|
|
41
|
-
? { pwnedPasswordOccurrence: password.count }
|
|
42
|
-
: null));
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
PasswordCheckerLibDirective.decorators = [
|
|
46
|
-
{ type: Directive, args: [{
|
|
47
|
-
// tslint:disable-next-line directive-selector
|
|
48
|
-
selector: '[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]',
|
|
49
|
-
providers: [
|
|
50
|
-
{
|
|
51
|
-
provide: NG_ASYNC_VALIDATORS,
|
|
52
|
-
useExisting: PasswordCheckerLibDirective,
|
|
53
|
-
multi: true,
|
|
54
|
-
},
|
|
55
|
-
]
|
|
56
|
-
},] }
|
|
57
|
-
];
|
|
58
|
-
PasswordCheckerLibDirective.ctorParameters = () => [
|
|
59
|
-
{ type: HttpClient },
|
|
60
|
-
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [PasswordCheckerConfigValue,] }] }
|
|
61
|
-
];
|
|
62
|
-
PasswordCheckerLibDirective.propDecorators = {
|
|
63
|
-
pwnedPasswordApi: [{ type: Input }],
|
|
64
|
-
pwnedPasswordMinimumOccurrenceForError: [{ type: Input }],
|
|
65
|
-
pwnedPasswordApiCallDebounceTime: [{ type: Input }]
|
|
66
|
-
};
|
|
67
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFzc3dvcmQtY2hlY2tlci1saWIuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvcGFzc3dvcmQtY2hlY2tlci1saWIvc3JjL2xpYi9wYXNzd29yZC1jaGVja2VyLWxpYi5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFjLEtBQUssRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN6QyxPQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2hELE9BQU8sRUFBbUMsbUJBQW1CLEVBQW9CLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEcsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNuRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEQsT0FBTyxJQUFJLE1BQU0sZ0JBQWdCLENBQUM7QUFDbEMsT0FBTyxFQUFrQywwQkFBMEIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBYXZHLE1BQU0sT0FBTywyQkFBMkI7SUFPdEMsWUFDVSxJQUFnQixFQUN3QixNQUFzQztRQUQ5RSxTQUFJLEdBQUosSUFBSSxDQUFZO1FBSXhCLElBQUksQ0FBQyxNQUFNLEVBQUU7WUFDWCxxREFBcUQ7WUFDckQsNkJBQTZCO1lBQzdCLE1BQU0sR0FBRyxFQUFFLENBQUM7U0FDYjtRQUVELElBQUksQ0FBQyxnQkFBZ0I7WUFDbkIsTUFBTSxDQUFDLGdCQUFnQjttQkFDcEIsdUNBQXVDLENBQUM7UUFDN0MsSUFBSSxDQUFDLHNDQUFzQztZQUN6QyxNQUFNLENBQUMsc0NBQXNDO21CQUMxQyxDQUFDLENBQUM7UUFDUCxJQUFJLENBQUMsZ0NBQWdDO1lBQ25DLE1BQU0sQ0FBQyxnQ0FBZ0M7bUJBQ3BDLEdBQUcsQ0FBQztJQUNYLENBQUM7SUFFRCxRQUFRLENBQUMsT0FBd0I7UUFDL0IsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFcEMsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLGdDQUFnQyxDQUFDLENBQUMsSUFBSSxDQUN0RCxHQUFHLENBQUMsR0FBRyxFQUFFO1lBQ1AsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBRWpELE9BQU87Z0JBQ0wsU0FBUyxFQUFFLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDakMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO2FBQzlCLENBQUM7UUFDSixDQUFDLENBQUMsRUFDRixTQUFTLENBQ1AsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUNyQixHQUFHLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsU0FBUyxFQUFFLEVBQUcsRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLENBQ3JFLENBQUMsSUFBSSxDQUNOLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsRUFDNUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFO1lBQ3hDLE1BQU0sS0FBSyxHQUFJLFFBQVEsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7WUFFbkMsT0FBTztnQkFDTCxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztnQkFDZCxLQUFLLEVBQUUsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUM7YUFDOUIsQ0FBQztRQUNKLENBQUMsQ0FDRixDQUFDLEVBQ0YsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQzlFLENBQ0YsRUFDRCxHQUFHLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxRQUFRLElBQUksUUFBUSxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsc0NBQXNDO1lBQ3ZGLENBQUMsQ0FBQyxFQUFFLHVCQUF1QixFQUFFLFFBQVEsQ0FBQyxLQUFLLEVBQUU7WUFDN0MsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUNWLENBQUM7SUFDSixDQUFDOzs7WUF6RUYsU0FBUyxTQUFDO2dCQUNULDhDQUE4QztnQkFDOUMsUUFBUSxFQUFFLG9IQUFvSDtnQkFDOUgsU0FBUyxFQUFFO29CQUNMO3dCQUNFLE9BQU8sRUFBRSxtQkFBbUI7d0JBQzVCLFdBQVcsRUFBRSwyQkFBMkI7d0JBQ3hDLEtBQUssRUFBRSxJQUFJO3FCQUNaO2lCQUNGO2FBQ047OztZQWRRLFVBQVU7NENBd0JkLFFBQVEsWUFBSSxNQUFNLFNBQUMsMEJBQTBCOzs7K0JBTi9DLEtBQUs7cURBQ0wsS0FBSzsrQ0FDTCxLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgT2JzZXJ2YWJsZSwgdGltZXIgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IG1hcCwgc3dpdGNoTWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgQWJzdHJhY3RDb250cm9sLCBBc3luY1ZhbGlkYXRvciwgTkdfQVNZTkNfVkFMSURBVE9SUywgVmFsaWRhdGlvbkVycm9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IERpcmVjdGl2ZSwgSW5qZWN0LCBJbnB1dCwgT3B0aW9uYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEh0dHBDbGllbnQgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgc2hhMSBmcm9tICdjcnlwdG8tanMvc2hhMSc7XG5pbXBvcnQgeyBQYXJ0aWFsLCBQYXNzd29yZENoZWNrZXJDb25maWcsIFBhc3N3b3JkQ2hlY2tlckNvbmZpZ1ZhbHVlIH0gZnJvbSAnLi9wYXNzd29yZC1jaGVja2VyLmNvbmZpZyc7XG5cbkBEaXJlY3RpdmUoe1xuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgZGlyZWN0aXZlLXNlbGVjdG9yXG4gIHNlbGVjdG9yOiAnW3B3bmVkUGFzc3dvcmRWYWxpZGF0b3JdW2Zvcm1Db250cm9sTmFtZV0sIFtwd25lZFBhc3N3b3JkVmFsaWRhdG9yXVtuZ01vZGVsXSxbcHduZWRQYXNzd29yZFZhbGlkYXRvcl1bZm9ybUNvbnRyb2xdJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBwcm92aWRlOiBOR19BU1lOQ19WQUxJREFUT1JTLFxuICAgICAgICAgIHVzZUV4aXN0aW5nOiBQYXNzd29yZENoZWNrZXJMaWJEaXJlY3RpdmUsXG4gICAgICAgICAgbXVsdGk6IHRydWUsXG4gICAgICAgIH0sXG4gICAgICBdXG59KVxuZXhwb3J0IGNsYXNzIFBhc3N3b3JkQ2hlY2tlckxpYkRpcmVjdGl2ZSBpbXBsZW1lbnRzIEFzeW5jVmFsaWRhdG9yIHtcbiAgcHJpdmF0ZSBwd25lZFBhc3N3b3JkTWluaW11bU9jY3VycmVuY2VGb3JFcnJvclZhbHVlOiBudW1iZXI7XG5cbiAgQElucHV0KCkgcHduZWRQYXNzd29yZEFwaTogc3RyaW5nO1xuICBASW5wdXQoKSBwd25lZFBhc3N3b3JkTWluaW11bU9jY3VycmVuY2VGb3JFcnJvcjogbnVtYmVyO1xuICBASW5wdXQoKSBwd25lZFBhc3N3b3JkQXBpQ2FsbERlYm91bmNlVGltZTogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgaHR0cDogSHR0cENsaWVudCxcbiAgICBAT3B0aW9uYWwoKSBASW5qZWN0KFBhc3N3b3JkQ2hlY2tlckNvbmZpZ1ZhbHVlKSBjb25maWc6IFBhcnRpYWw8UGFzc3dvcmRDaGVja2VyQ29uZmlnPixcbiAgICApIHtcblxuICAgIGlmICghY29uZmlnKSB7XG4gICAgICAvLyBkZWZhdWx0IGluaXRpYWxpemF0aW9uIGluIGNvbnN0cnVjdG9yIGRpZG4ndCB3b3JrLlxuICAgICAgLy8gY29uZmxpY3Qgd2l0aCBAT3B0aW9uYWwoKT9cbiAgICAgIGNvbmZpZyA9IHt9O1xuICAgIH1cblxuICAgIHRoaXMucHduZWRQYXNzd29yZEFwaSA9XG4gICAgICBjb25maWcucHduZWRQYXNzd29yZEFwaVxuICAgICAgfHwgJ2h0dHBzOi8vYXBpLnB3bmVkcGFzc3dvcmRzLmNvbS9yYW5nZS8nO1xuICAgIHRoaXMucHduZWRQYXNzd29yZE1pbmltdW1PY2N1cnJlbmNlRm9yRXJyb3IgPVxuICAgICAgY29uZmlnLnB3bmVkUGFzc3dvcmRNaW5pbXVtT2NjdXJyZW5jZUZvckVycm9yXG4gICAgICB8fCAxO1xuICAgIHRoaXMucHduZWRQYXNzd29yZEFwaUNhbGxEZWJvdW5jZVRpbWUgPVxuICAgICAgY29uZmlnLnB3bmVkUGFzc3dvcmRBcGlDYWxsRGVib3VuY2VUaW1lXG4gICAgICB8fCA0MDA7XG4gIH1cblxuICB2YWxpZGF0ZShjb250cm9sOiBBYnN0cmFjdENvbnRyb2wpOiBPYnNlcnZhYmxlPFZhbGlkYXRpb25FcnJvcnN8bnVsbD4ge1xuICAgIGNvbnN0IHB3ID0gJycuY29uY2F0KGNvbnRyb2wudmFsdWUpO1xuXG4gICAgcmV0dXJuIHRpbWVyKHRoaXMucHduZWRQYXNzd29yZEFwaUNhbGxEZWJvdW5jZVRpbWUpLnBpcGUoXG4gICAgICBtYXAoKCkgPT4ge1xuICAgICAgICBjb25zdCBwd1NoYTEgPSBzaGExKHB3KS50b1N0cmluZygpLnRvVXBwZXJDYXNlKCk7XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBmaXJzdFBhcnQ6IHB3U2hhMS5zdWJzdHJpbmcoMCwgNSksXG4gICAgICAgICAgbGFzdFBhcnQ6IHB3U2hhMS5zdWJzdHJpbmcoNSksXG4gICAgICAgIH07XG4gICAgICB9KSxcbiAgICAgIHN3aXRjaE1hcChcbiAgICAgICAgKGhhc2gpID0+IHRoaXMuaHR0cC5nZXQoXG4gICAgICAgICAgYCR7dGhpcy5wd25lZFBhc3N3b3JkQXBpfSR7aGFzaC5maXJzdFBhcnR9YCwgIHsgcmVzcG9uc2VUeXBlOiAndGV4dCcgfVxuICAgICAgICAgICkucGlwZShcbiAgICAgICAgICBtYXAocGFzc3dvcmRzID0+IHBhc3N3b3Jkcy5zcGxpdCgvW1xcclxcbl0rLykpLFxuICAgICAgICAgIG1hcChwYXNzd29yZHMgPT4gcGFzc3dvcmRzLm1hcCgocGFzc3dvcmQpID0+IHtcbiAgICAgICAgICAgICAgY29uc3Qgc3BsaXQgPSAgcGFzc3dvcmQuc3BsaXQoJzonKTtcblxuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGhhc2g6IHNwbGl0WzBdLFxuICAgICAgICAgICAgICAgIGNvdW50OiBwYXJzZUludChzcGxpdFsxXSwgMTApLFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICkpLFxuICAgICAgICAgIG1hcChwYXNzd29yZHMgPT4gcGFzc3dvcmRzLmZpbmQocGFzc3dvcmQgPT4gcGFzc3dvcmQuaGFzaCA9PT0gaGFzaC5sYXN0UGFydCkpLFxuICAgICAgICApLFxuICAgICAgKSxcbiAgICAgIG1hcChwYXNzd29yZCA9PiBwYXNzd29yZCAmJiBwYXNzd29yZC5jb3VudCA+PSB0aGlzLnB3bmVkUGFzc3dvcmRNaW5pbXVtT2NjdXJyZW5jZUZvckVycm9yXG4gICAgICAgID8geyBwd25lZFBhc3N3b3JkT2NjdXJyZW5jZTogcGFzc3dvcmQuY291bnQgfVxuICAgICAgICA6IG51bGwpLFxuICAgICk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { NgModule } from '@angular/core';
|
|
2
|
-
import { PasswordCheckerLibDirective } from './password-checker-lib.directive';
|
|
3
|
-
import { HttpClientModule } from '@angular/common/http';
|
|
4
|
-
import { PasswordCheckerConfigValue } from './password-checker.config';
|
|
5
|
-
export class PasswordCheckerModule {
|
|
6
|
-
static forRoot(config = {}) {
|
|
7
|
-
return {
|
|
8
|
-
ngModule: PasswordCheckerModule,
|
|
9
|
-
providers: [
|
|
10
|
-
{
|
|
11
|
-
provide: PasswordCheckerConfigValue,
|
|
12
|
-
useValue: config,
|
|
13
|
-
}
|
|
14
|
-
]
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
PasswordCheckerModule.decorators = [
|
|
19
|
-
{ type: NgModule, args: [{
|
|
20
|
-
declarations: [PasswordCheckerLibDirective],
|
|
21
|
-
imports: [HttpClientModule],
|
|
22
|
-
exports: [PasswordCheckerLibDirective]
|
|
23
|
-
},] }
|
|
24
|
-
];
|
|
25
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFzc3dvcmQtY2hlY2tlci1saWIubW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvcGFzc3dvcmQtY2hlY2tlci1saWIvc3JjL2xpYi9wYXNzd29yZC1jaGVja2VyLWxpYi5tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUF1QixRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDOUQsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDL0UsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDeEQsT0FBTyxFQUFrQywwQkFBMEIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBT3ZHLE1BQU0sT0FBTyxxQkFBcUI7SUFDaEMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUF5QyxFQUFFO1FBQ3hELE9BQU87WUFDTCxRQUFRLEVBQUUscUJBQXFCO1lBQy9CLFNBQVMsRUFBRTtnQkFDVDtvQkFDRSxPQUFPLEVBQUUsMEJBQTBCO29CQUNuQyxRQUFRLEVBQUUsTUFBTTtpQkFDakI7YUFDRjtTQUNGLENBQUM7SUFDSixDQUFDOzs7WUFoQkYsUUFBUSxTQUFDO2dCQUNSLFlBQVksRUFBRSxDQUFDLDJCQUEyQixDQUFDO2dCQUMzQyxPQUFPLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDM0IsT0FBTyxFQUFFLENBQUMsMkJBQTJCLENBQUM7YUFDdkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBNb2R1bGVXaXRoUHJvdmlkZXJzLCBOZ01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgUGFzc3dvcmRDaGVja2VyTGliRGlyZWN0aXZlIH0gZnJvbSAnLi9wYXNzd29yZC1jaGVja2VyLWxpYi5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgSHR0cENsaWVudE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IFBhcnRpYWwsIFBhc3N3b3JkQ2hlY2tlckNvbmZpZywgUGFzc3dvcmRDaGVja2VyQ29uZmlnVmFsdWUgfSBmcm9tICcuL3Bhc3N3b3JkLWNoZWNrZXIuY29uZmlnJztcblxuQE5nTW9kdWxlKHtcbiAgZGVjbGFyYXRpb25zOiBbUGFzc3dvcmRDaGVja2VyTGliRGlyZWN0aXZlXSxcbiAgaW1wb3J0czogW0h0dHBDbGllbnRNb2R1bGVdLFxuICBleHBvcnRzOiBbUGFzc3dvcmRDaGVja2VyTGliRGlyZWN0aXZlXVxufSlcbmV4cG9ydCBjbGFzcyBQYXNzd29yZENoZWNrZXJNb2R1bGUge1xuICBzdGF0aWMgZm9yUm9vdChjb25maWc6IFBhcnRpYWw8UGFzc3dvcmRDaGVja2VyQ29uZmlnPiA9IHt9KTogTW9kdWxlV2l0aFByb3ZpZGVyczxQYXNzd29yZENoZWNrZXJNb2R1bGU+IHtcbiAgICByZXR1cm4ge1xuICAgICAgbmdNb2R1bGU6IFBhc3N3b3JkQ2hlY2tlck1vZHVsZSxcbiAgICAgIHByb3ZpZGVyczogW1xuICAgICAgICB7XG4gICAgICAgICAgcHJvdmlkZTogUGFzc3dvcmRDaGVja2VyQ29uZmlnVmFsdWUsXG4gICAgICAgICAgdXNlVmFsdWU6IGNvbmZpZyxcbiAgICAgICAgfVxuICAgICAgXVxuICAgIH07XG4gIH1cbn1cbiJdfQ==
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generated bundle index. Do not edit.
|
|
3
|
-
*/
|
|
4
|
-
export * from './public_api';
|
|
5
|
-
export { PasswordCheckerConfigValue as ɵb } from './lib/password-checker.config';
|
|
6
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJpYW5ndWxhci1wYXNzd29yZC1jaGVja2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcHJvamVjdHMvcGFzc3dvcmQtY2hlY2tlci1saWIvc3JjL3RyaWFuZ3VsYXItcGFzc3dvcmQtY2hlY2tlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsY0FBYyxDQUFDO0FBRTdCLE9BQU8sRUFBZSwwQkFBMEIsSUFBSSxFQUFFLEVBQUMsTUFBTSwrQkFBK0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9wdWJsaWNfYXBpJztcblxuZXhwb3J0IHtQYXJ0aWFsIGFzIMm1YSxQYXNzd29yZENoZWNrZXJDb25maWdWYWx1ZSBhcyDJtWJ9IGZyb20gJy4vbGliL3Bhc3N3b3JkLWNoZWNrZXIuY29uZmlnJzsiXX0=
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { timer } from 'rxjs';
|
|
2
|
-
import { map, switchMap } from 'rxjs/operators';
|
|
3
|
-
import { NG_ASYNC_VALIDATORS } from '@angular/forms';
|
|
4
|
-
import { InjectionToken, Directive, Optional, Inject, Input, NgModule } from '@angular/core';
|
|
5
|
-
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
|
6
|
-
import sha1 from 'crypto-js/sha1';
|
|
7
|
-
|
|
8
|
-
const PasswordCheckerConfigValue = new InjectionToken('PASSWORD_CHECKER_CONFIG');
|
|
9
|
-
|
|
10
|
-
class PasswordCheckerLibDirective {
|
|
11
|
-
constructor(http, config) {
|
|
12
|
-
this.http = http;
|
|
13
|
-
if (!config) {
|
|
14
|
-
// default initialization in constructor didn't work.
|
|
15
|
-
// conflict with @Optional()?
|
|
16
|
-
config = {};
|
|
17
|
-
}
|
|
18
|
-
this.pwnedPasswordApi =
|
|
19
|
-
config.pwnedPasswordApi
|
|
20
|
-
|| 'https://api.pwnedpasswords.com/range/';
|
|
21
|
-
this.pwnedPasswordMinimumOccurrenceForError =
|
|
22
|
-
config.pwnedPasswordMinimumOccurrenceForError
|
|
23
|
-
|| 1;
|
|
24
|
-
this.pwnedPasswordApiCallDebounceTime =
|
|
25
|
-
config.pwnedPasswordApiCallDebounceTime
|
|
26
|
-
|| 400;
|
|
27
|
-
}
|
|
28
|
-
validate(control) {
|
|
29
|
-
const pw = ''.concat(control.value);
|
|
30
|
-
return timer(this.pwnedPasswordApiCallDebounceTime).pipe(map(() => {
|
|
31
|
-
const pwSha1 = sha1(pw).toString().toUpperCase();
|
|
32
|
-
return {
|
|
33
|
-
firstPart: pwSha1.substring(0, 5),
|
|
34
|
-
lastPart: pwSha1.substring(5),
|
|
35
|
-
};
|
|
36
|
-
}), switchMap((hash) => this.http.get(`${this.pwnedPasswordApi}${hash.firstPart}`, { responseType: 'text' }).pipe(map(passwords => passwords.split(/[\r\n]+/)), map(passwords => passwords.map((password) => {
|
|
37
|
-
const split = password.split(':');
|
|
38
|
-
return {
|
|
39
|
-
hash: split[0],
|
|
40
|
-
count: parseInt(split[1], 10),
|
|
41
|
-
};
|
|
42
|
-
})), map(passwords => passwords.find(password => password.hash === hash.lastPart)))), map(password => password && password.count >= this.pwnedPasswordMinimumOccurrenceForError
|
|
43
|
-
? { pwnedPasswordOccurrence: password.count }
|
|
44
|
-
: null));
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
PasswordCheckerLibDirective.decorators = [
|
|
48
|
-
{ type: Directive, args: [{
|
|
49
|
-
// tslint:disable-next-line directive-selector
|
|
50
|
-
selector: '[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]',
|
|
51
|
-
providers: [
|
|
52
|
-
{
|
|
53
|
-
provide: NG_ASYNC_VALIDATORS,
|
|
54
|
-
useExisting: PasswordCheckerLibDirective,
|
|
55
|
-
multi: true,
|
|
56
|
-
},
|
|
57
|
-
]
|
|
58
|
-
},] }
|
|
59
|
-
];
|
|
60
|
-
PasswordCheckerLibDirective.ctorParameters = () => [
|
|
61
|
-
{ type: HttpClient },
|
|
62
|
-
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [PasswordCheckerConfigValue,] }] }
|
|
63
|
-
];
|
|
64
|
-
PasswordCheckerLibDirective.propDecorators = {
|
|
65
|
-
pwnedPasswordApi: [{ type: Input }],
|
|
66
|
-
pwnedPasswordMinimumOccurrenceForError: [{ type: Input }],
|
|
67
|
-
pwnedPasswordApiCallDebounceTime: [{ type: Input }]
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
class PasswordCheckerModule {
|
|
71
|
-
static forRoot(config = {}) {
|
|
72
|
-
return {
|
|
73
|
-
ngModule: PasswordCheckerModule,
|
|
74
|
-
providers: [
|
|
75
|
-
{
|
|
76
|
-
provide: PasswordCheckerConfigValue,
|
|
77
|
-
useValue: config,
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
PasswordCheckerModule.decorators = [
|
|
84
|
-
{ type: NgModule, args: [{
|
|
85
|
-
declarations: [PasswordCheckerLibDirective],
|
|
86
|
-
imports: [HttpClientModule],
|
|
87
|
-
exports: [PasswordCheckerLibDirective]
|
|
88
|
-
},] }
|
|
89
|
-
];
|
|
90
|
-
|
|
91
|
-
/*
|
|
92
|
-
* Public API Surface of password-checker-lib
|
|
93
|
-
*/
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Generated bundle index. Do not edit.
|
|
97
|
-
*/
|
|
98
|
-
|
|
99
|
-
export { PasswordCheckerLibDirective, PasswordCheckerModule, PasswordCheckerConfigValue as ɵb };
|
|
100
|
-
//# sourceMappingURL=triangular-password-checker.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"triangular-password-checker.js","sources":["../../../projects/password-checker-lib/src/lib/password-checker.config.ts","../../../projects/password-checker-lib/src/lib/password-checker-lib.directive.ts","../../../projects/password-checker-lib/src/lib/password-checker-lib.module.ts","../../../projects/password-checker-lib/src/public_api.ts","../../../projects/password-checker-lib/src/triangular-password-checker.ts"],"sourcesContent":["import {InjectionToken} from '@angular/core';\n\nexport type Partial<T> = {\n [P in keyof T]?: T[P];\n};\n\nexport interface PasswordCheckerConfig {\n pwnedPasswordApi: string;\n pwnedPasswordMinimumOccurrenceForError: number;\n pwnedPasswordApiCallDebounceTime: number;\n}\n\nexport const PasswordCheckerConfigValue = new InjectionToken<Partial<PasswordCheckerConfig>>('PASSWORD_CHECKER_CONFIG');\n","import { Observable, timer } from 'rxjs';\nimport { map, switchMap } from 'rxjs/operators';\nimport { AbstractControl, AsyncValidator, NG_ASYNC_VALIDATORS, ValidationErrors } from '@angular/forms';\nimport { Directive, Inject, Input, Optional } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport sha1 from 'crypto-js/sha1';\nimport { Partial, PasswordCheckerConfig, PasswordCheckerConfigValue } from './password-checker.config';\n\n@Directive({\n // tslint:disable-next-line directive-selector\n selector: '[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]',\n providers: [\n {\n provide: NG_ASYNC_VALIDATORS,\n useExisting: PasswordCheckerLibDirective,\n multi: true,\n },\n ]\n})\nexport class PasswordCheckerLibDirective implements AsyncValidator {\n private pwnedPasswordMinimumOccurrenceForErrorValue: number;\n\n @Input() pwnedPasswordApi: string;\n @Input() pwnedPasswordMinimumOccurrenceForError: number;\n @Input() pwnedPasswordApiCallDebounceTime: number;\n\n constructor(\n private http: HttpClient,\n @Optional() @Inject(PasswordCheckerConfigValue) config: Partial<PasswordCheckerConfig>,\n ) {\n\n if (!config) {\n // default initialization in constructor didn't work.\n // conflict with @Optional()?\n config = {};\n }\n\n this.pwnedPasswordApi =\n config.pwnedPasswordApi\n || 'https://api.pwnedpasswords.com/range/';\n this.pwnedPasswordMinimumOccurrenceForError =\n config.pwnedPasswordMinimumOccurrenceForError\n || 1;\n this.pwnedPasswordApiCallDebounceTime =\n config.pwnedPasswordApiCallDebounceTime\n || 400;\n }\n\n validate(control: AbstractControl): Observable<ValidationErrors|null> {\n const pw = ''.concat(control.value);\n\n return timer(this.pwnedPasswordApiCallDebounceTime).pipe(\n map(() => {\n const pwSha1 = sha1(pw).toString().toUpperCase();\n\n return {\n firstPart: pwSha1.substring(0, 5),\n lastPart: pwSha1.substring(5),\n };\n }),\n switchMap(\n (hash) => this.http.get(\n `${this.pwnedPasswordApi}${hash.firstPart}`, { responseType: 'text' }\n ).pipe(\n map(passwords => passwords.split(/[\\r\\n]+/)),\n map(passwords => passwords.map((password) => {\n const split = password.split(':');\n\n return {\n hash: split[0],\n count: parseInt(split[1], 10),\n };\n }\n )),\n map(passwords => passwords.find(password => password.hash === hash.lastPart)),\n ),\n ),\n map(password => password && password.count >= this.pwnedPasswordMinimumOccurrenceForError\n ? { pwnedPasswordOccurrence: password.count }\n : null),\n );\n }\n}\n","import { ModuleWithProviders, NgModule } from '@angular/core';\nimport { PasswordCheckerLibDirective } from './password-checker-lib.directive';\nimport { HttpClientModule } from '@angular/common/http';\nimport { Partial, PasswordCheckerConfig, PasswordCheckerConfigValue } from './password-checker.config';\n\n@NgModule({\n declarations: [PasswordCheckerLibDirective],\n imports: [HttpClientModule],\n exports: [PasswordCheckerLibDirective]\n})\nexport class PasswordCheckerModule {\n static forRoot(config: Partial<PasswordCheckerConfig> = {}): ModuleWithProviders<PasswordCheckerModule> {\n return {\n ngModule: PasswordCheckerModule,\n providers: [\n {\n provide: PasswordCheckerConfigValue,\n useValue: config,\n }\n ]\n };\n }\n}\n","/*\n * Public API Surface of password-checker-lib\n */\n\nexport * from './lib/password-checker-lib.directive';\nexport * from './lib/password-checker-lib.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n\nexport {Partial as ɵa,PasswordCheckerConfigValue as ɵb} from './lib/password-checker.config';"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"__symbolic":"module","version":4,"metadata":{"PasswordCheckerLibDirective":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Directive","line":8,"character":1},"arguments":[{"selector":"[pwnedPasswordValidator][formControlName], [pwnedPasswordValidator][ngModel],[pwnedPasswordValidator][formControl]","providers":[{"provide":{"__symbolic":"reference","module":"@angular/forms","name":"NG_ASYNC_VALIDATORS","line":13,"character":19},"useExisting":{"__symbolic":"reference","name":"PasswordCheckerLibDirective"},"multi":true}]}]}],"members":{"pwnedPasswordApi":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input","line":22,"character":3}}]}],"pwnedPasswordMinimumOccurrenceForError":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input","line":23,"character":3}}]}],"pwnedPasswordApiCallDebounceTime":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input","line":24,"character":3}}]}],"__ctor__":[{"__symbolic":"constructor","parameterDecorators":[null,[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Optional","line":28,"character":5}},{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Inject","line":28,"character":17},"arguments":[{"__symbolic":"reference","name":"ɵb"}]}]],"parameters":[{"__symbolic":"reference","module":"@angular/common/http","name":"HttpClient","line":27,"character":18},{"__symbolic":"reference","name":"ɵa"}]}],"validate":[{"__symbolic":"method"}]}},"PasswordCheckerModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule","line":5,"character":1},"arguments":[{"declarations":[{"__symbolic":"reference","name":"PasswordCheckerLibDirective"}],"imports":[{"__symbolic":"reference","module":"@angular/common/http","name":"HttpClientModule","line":7,"character":12}],"exports":[{"__symbolic":"reference","name":"PasswordCheckerLibDirective"}]}]}],"members":{},"statics":{"forRoot":{"__symbolic":"function","parameters":["config"],"defaults":[{}],"value":{"ngModule":{"__symbolic":"reference","name":"PasswordCheckerModule"},"providers":[{"provide":{"__symbolic":"reference","name":"ɵb"},"useValue":{"__symbolic":"reference","name":"config"}}]}}}},"ɵa":{"__symbolic":"interface"},"ɵb":{"__symbolic":"new","expression":{"__symbolic":"reference","module":"@angular/core","name":"InjectionToken","line":12,"character":46},"arguments":["PASSWORD_CHECKER_CONFIG"]}},"origins":{"PasswordCheckerLibDirective":"./lib/password-checker-lib.directive","PasswordCheckerModule":"./lib/password-checker-lib.module","ɵa":"./lib/password-checker.config","ɵb":"./lib/password-checker.config"},"importAs":"@triangular/password-checker"}
|