ssi-security-commons 0.16.27 → 0.16.29
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/esm2022/lib/services/auth-interceptor.service.mjs +21 -10
- package/esm2022/lib/services/hybrid-encryption.service.mjs +70 -0
- package/esm2022/lib/services/session.service.mjs +3 -2
- package/esm2022/lib/services/web-authn.service.mjs +17 -2
- package/esm2022/lib/user.model.mjs +1 -1
- package/fesm2022/ssi-security-commons.mjs +104 -10
- package/fesm2022/ssi-security-commons.mjs.map +1 -1
- package/lib/services/auth-interceptor.service.d.ts +3 -1
- package/lib/services/hybrid-encryption.service.d.ts +20 -0
- package/lib/services/web-authn.service.d.ts +1 -0
- package/lib/user.model.d.ts +1 -0
- package/package.json +1 -1
|
@@ -11,9 +11,9 @@ import * as i3 from '@angular/common';
|
|
|
11
11
|
import { CommonModule } from '@angular/common';
|
|
12
12
|
import * as i1$1 from '@angular/common/http';
|
|
13
13
|
import { HttpHeaders, HttpResponse, HttpErrorResponse } from '@angular/common/http';
|
|
14
|
-
import { map,
|
|
15
|
-
import { BehaviorSubject, throwError, map as map$1 } from 'rxjs';
|
|
16
|
-
import * as
|
|
14
|
+
import { map, switchMap, catchError, filter, take } from 'rxjs/operators';
|
|
15
|
+
import { from, BehaviorSubject, throwError, map as map$1 } from 'rxjs';
|
|
16
|
+
import * as i3$1 from '@angular/router';
|
|
17
17
|
|
|
18
18
|
class SsiSecurityCommonsService {
|
|
19
19
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: SsiSecurityCommonsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
@@ -167,7 +167,8 @@ class SessionService {
|
|
|
167
167
|
username: tokenData.preferred_username,
|
|
168
168
|
email: tokenData.email,
|
|
169
169
|
emailVerified: tokenData.email_verified,
|
|
170
|
-
countryCode: tokenData.country_code
|
|
170
|
+
countryCode: tokenData.country_code,
|
|
171
|
+
partyId: tokenData.party_id
|
|
171
172
|
};
|
|
172
173
|
return userData;
|
|
173
174
|
}
|
|
@@ -894,10 +895,79 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImpor
|
|
|
894
895
|
}]
|
|
895
896
|
}] });
|
|
896
897
|
|
|
898
|
+
class HybridEncryptionService {
|
|
899
|
+
constructor() {
|
|
900
|
+
this.publicKeyPem = `-----BEGIN PUBLIC KEY-----
|
|
901
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydjMaPDQvcNCPsB3zmuA
|
|
902
|
+
RyDw/eVPjH8eITcWq+TnmqW4FCxwTxAQQy8bEnO7HC8eUVaD8tlNaLVjiRRCo0+o
|
|
903
|
+
JMDZC5S9aUGpz/Ueghp5aziu0abk7pZ+x/BrfpAN+7VteZh00d/YAtZlbQ6kHM44
|
|
904
|
+
oz2d7Fj1MPzB22ZoEnmcFqBlvsW8yblM38HEAKRXj9733XiayDoq6ivP046IFBpP
|
|
905
|
+
Cgg7kOLfOYMt7ZNkaKzDeYBfQAvhW+Nd6EN+8CCrI8//fnwRbrItzgR5KXwJ0F5T
|
|
906
|
+
w6/YhIkJi7Ce6kR8D7aYdXNoRKzX5m+GxSkLtiMImHOnVWg+wo/lvCbLRWS+QQ14
|
|
907
|
+
pQIDAQAB
|
|
908
|
+
-----END PUBLIC KEY-----`;
|
|
909
|
+
this.loadPublicKey();
|
|
910
|
+
}
|
|
911
|
+
/** Import RSA public key */
|
|
912
|
+
async loadPublicKey() {
|
|
913
|
+
const pemHeader = '-----BEGIN PUBLIC KEY-----';
|
|
914
|
+
const pemFooter = '-----END PUBLIC KEY-----';
|
|
915
|
+
const pemContents = this.publicKeyPem
|
|
916
|
+
.replace(pemHeader, '')
|
|
917
|
+
.replace(pemFooter, '')
|
|
918
|
+
.replace(/\s/g, '');
|
|
919
|
+
const binaryDer = Uint8Array.from(atob(pemContents), c => c.charCodeAt(0));
|
|
920
|
+
this.publicKey = await crypto.subtle.importKey('spki', binaryDer.buffer, {
|
|
921
|
+
name: 'RSA-OAEP',
|
|
922
|
+
hash: 'SHA-256'
|
|
923
|
+
}, true, ['encrypt']);
|
|
924
|
+
}
|
|
925
|
+
/** Generate a random AES key */
|
|
926
|
+
async generateAesKey() {
|
|
927
|
+
return crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']);
|
|
928
|
+
}
|
|
929
|
+
/** Encrypt large data with AES and AES key with RSA */
|
|
930
|
+
async encrypt(data) {
|
|
931
|
+
if (!this.publicKey) {
|
|
932
|
+
await this.loadPublicKey();
|
|
933
|
+
}
|
|
934
|
+
// Convert payload to JSON + Uint8Array
|
|
935
|
+
const encoder = new TextEncoder();
|
|
936
|
+
const plainBytes = encoder.encode(JSON.stringify(data));
|
|
937
|
+
// Generate AES key + IV
|
|
938
|
+
const aesKey = await this.generateAesKey();
|
|
939
|
+
const iv = crypto.getRandomValues(new Uint8Array(12)); // AES-GCM nonce
|
|
940
|
+
// Encrypt data with AES
|
|
941
|
+
const encryptedDataBuffer = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, aesKey, plainBytes);
|
|
942
|
+
// Export AES key
|
|
943
|
+
const rawAesKey = await crypto.subtle.exportKey('raw', aesKey);
|
|
944
|
+
// Encrypt AES key with RSA
|
|
945
|
+
const encryptedKeyBuffer = await crypto.subtle.encrypt({ name: 'RSA-OAEP' }, this.publicKey, rawAesKey);
|
|
946
|
+
return {
|
|
947
|
+
encryptedKey: this.arrayBufferToBase64(encryptedKeyBuffer),
|
|
948
|
+
encryptedData: this.arrayBufferToBase64(encryptedDataBuffer),
|
|
949
|
+
iv: this.arrayBufferToBase64(iv.buffer)
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
/** Convert ArrayBuffer → Base64 */
|
|
953
|
+
arrayBufferToBase64(buffer) {
|
|
954
|
+
return btoa(String.fromCharCode(...new Uint8Array(buffer)));
|
|
955
|
+
}
|
|
956
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: HybridEncryptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
957
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: HybridEncryptionService, providedIn: 'root' }); }
|
|
958
|
+
}
|
|
959
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: HybridEncryptionService, decorators: [{
|
|
960
|
+
type: Injectable,
|
|
961
|
+
args: [{
|
|
962
|
+
providedIn: 'root'
|
|
963
|
+
}]
|
|
964
|
+
}], ctorParameters: function () { return []; } });
|
|
965
|
+
|
|
897
966
|
/* eslint-disable */
|
|
898
967
|
class AuthInterceptor {
|
|
899
|
-
constructor(cryptoService, environment) {
|
|
968
|
+
constructor(cryptoService, hybridEncryptionService, environment) {
|
|
900
969
|
this.cryptoService = cryptoService;
|
|
970
|
+
this.hybridEncryptionService = hybridEncryptionService;
|
|
901
971
|
console.log('AuthInterceptor constructor');
|
|
902
972
|
this.environment = environment;
|
|
903
973
|
}
|
|
@@ -937,14 +1007,23 @@ class AuthInterceptor {
|
|
|
937
1007
|
headers: request.headers.append('Language', l)
|
|
938
1008
|
});
|
|
939
1009
|
}
|
|
1010
|
+
const isEncrypted = request.headers.get('X-Encrypted');
|
|
1011
|
+
if (isEncrypted === 'true' && request.body) {
|
|
1012
|
+
return from(this.hybridEncryptionService.encrypt(request.body)).pipe(switchMap(encryptedPayload => {
|
|
1013
|
+
const newReq = request.clone({
|
|
1014
|
+
body: encryptedPayload
|
|
1015
|
+
});
|
|
1016
|
+
return next.handle(newReq);
|
|
1017
|
+
}));
|
|
1018
|
+
}
|
|
940
1019
|
return next.handle(request);
|
|
941
1020
|
}
|
|
942
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: AuthInterceptor, deps: [{ token: CryptoService }, { token: 'environment' }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1021
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: AuthInterceptor, deps: [{ token: CryptoService }, { token: HybridEncryptionService }, { token: 'environment' }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
943
1022
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: AuthInterceptor }); }
|
|
944
1023
|
}
|
|
945
1024
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: AuthInterceptor, decorators: [{
|
|
946
1025
|
type: Injectable
|
|
947
|
-
}], ctorParameters: function () { return [{ type: CryptoService }, { type: undefined, decorators: [{
|
|
1026
|
+
}], ctorParameters: function () { return [{ type: CryptoService }, { type: HybridEncryptionService }, { type: undefined, decorators: [{
|
|
948
1027
|
type: Inject,
|
|
949
1028
|
args: ['environment']
|
|
950
1029
|
}] }]; } });
|
|
@@ -1041,12 +1120,12 @@ class ResponseInterceptor {
|
|
|
1041
1120
|
console.error(err);
|
|
1042
1121
|
});
|
|
1043
1122
|
}
|
|
1044
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: ResponseInterceptor, deps: [{ token: i0.Injector }, { token:
|
|
1123
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: ResponseInterceptor, deps: [{ token: i0.Injector }, { token: i3$1.Router }, { token: CryptoService }, { token: JwtService }, { token: SessionService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1045
1124
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: ResponseInterceptor }); }
|
|
1046
1125
|
}
|
|
1047
1126
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: ResponseInterceptor, decorators: [{
|
|
1048
1127
|
type: Injectable
|
|
1049
|
-
}], ctorParameters: function () { return [{ type: i0.Injector }, { type:
|
|
1128
|
+
}], ctorParameters: function () { return [{ type: i0.Injector }, { type: i3$1.Router }, { type: CryptoService }, { type: JwtService }, { type: SessionService }]; } });
|
|
1050
1129
|
|
|
1051
1130
|
/* eslint-disable max-lines-per-function */
|
|
1052
1131
|
/* eslint-disable prefer-const */
|
|
@@ -1102,9 +1181,24 @@ class WebAuthnService {
|
|
|
1102
1181
|
};
|
|
1103
1182
|
return navigator.credentials.get({ publicKey: publicKeyCredentials });
|
|
1104
1183
|
}
|
|
1105
|
-
|
|
1184
|
+
getChallengeOld() {
|
|
1106
1185
|
return Uint8Array.from('jEfcn1CsGFxBiXYtJMSGDycPqPoyFJ3Z', c => c.charCodeAt(0));
|
|
1107
1186
|
}
|
|
1187
|
+
getChallenge() {
|
|
1188
|
+
let base64 = 'jEfcn1CsGFxBiXYtJMSGDycPqPoyFJ3Z'
|
|
1189
|
+
.replace(/-/g, '+')
|
|
1190
|
+
.replace(/_/g, '/');
|
|
1191
|
+
while (base64.length % 4) {
|
|
1192
|
+
base64 += '=';
|
|
1193
|
+
}
|
|
1194
|
+
const binaryString = atob(base64);
|
|
1195
|
+
const len = binaryString.length;
|
|
1196
|
+
const bytes = new Uint8Array(len);
|
|
1197
|
+
for (let i = 0; i < len; i++) {
|
|
1198
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
1199
|
+
}
|
|
1200
|
+
return bytes;
|
|
1201
|
+
}
|
|
1108
1202
|
register(user, newCredentialInfo) {
|
|
1109
1203
|
const promise = new Promise((resolve, reject) => {
|
|
1110
1204
|
let enc = new TextDecoder('utf-8');
|