@experteam-mx/ngx-services 20.8.6 → 20.8.9
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.
|
@@ -5582,16 +5582,80 @@ var DocumentStatusCode;
|
|
|
5582
5582
|
DocumentStatusCode[DocumentStatusCode["WITH_ERRORS"] = 3] = "WITH_ERRORS";
|
|
5583
5583
|
})(DocumentStatusCode || (DocumentStatusCode = {}));
|
|
5584
5584
|
|
|
5585
|
+
const SOCKETS_AUTH_PATH = '/sockets/auth';
|
|
5585
5586
|
class WebSocketsService {
|
|
5586
|
-
pusher;
|
|
5587
|
+
pusher = null;
|
|
5588
|
+
appKey = null;
|
|
5589
|
+
connectPromise = null;
|
|
5587
5590
|
environments = inject(ENVIRONMENT_TOKEN);
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5591
|
+
getAuthToken = null;
|
|
5592
|
+
channelAuthHeaders = {};
|
|
5593
|
+
/**
|
|
5594
|
+
* Stores the Pusher/Soketi application key without opening a connection.
|
|
5595
|
+
* The first `channelSub` / `eventBind` opens Pusher via `ensureConnected`.
|
|
5596
|
+
*
|
|
5597
|
+
* @param {string} appKey - The Pusher/Soketi application key.
|
|
5598
|
+
*/
|
|
5599
|
+
setAppKey(appKey) {
|
|
5600
|
+
this.appKey = appKey;
|
|
5601
|
+
}
|
|
5602
|
+
/**
|
|
5603
|
+
* Registers a live token provider used when authorizing private/presence channels.
|
|
5604
|
+
* The provider is called at subscribe/authorize time; the token is not snapshotted here.
|
|
5605
|
+
*
|
|
5606
|
+
* @param {() => string | null} getToken - Returns the current session token, or null.
|
|
5607
|
+
*/
|
|
5608
|
+
setAuthTokenProvider(getToken) {
|
|
5609
|
+
this.getAuthToken = getToken;
|
|
5610
|
+
}
|
|
5611
|
+
/**
|
|
5612
|
+
* Connects to Pusher using the given app key and env `sockets` url/port/debug.
|
|
5613
|
+
* No-ops if already connected with the same key; reconnects if the key changed.
|
|
5614
|
+
* Resolves false when `sockets` is missing from the environment.
|
|
5615
|
+
* Apps should store the key with `setAppKey` and let subscribe open the client.
|
|
5616
|
+
*
|
|
5617
|
+
* @param {string} appKey - The Pusher/Soketi application key.
|
|
5618
|
+
* @return {Promise<Pusher | false>} The Pusher instance, or false when sockets are not configured.
|
|
5619
|
+
*/
|
|
5620
|
+
connect(appKey) {
|
|
5621
|
+
this.setAppKey(appKey);
|
|
5622
|
+
return new Promise((resolve) => {
|
|
5623
|
+
if (this.pusher && this.appKey === appKey) {
|
|
5624
|
+
return resolve(this.pusher);
|
|
5625
|
+
}
|
|
5626
|
+
const { sockets } = this.environments;
|
|
5627
|
+
if (!sockets)
|
|
5628
|
+
return resolve(false);
|
|
5629
|
+
if (this.pusher) {
|
|
5630
|
+
this.pusher.disconnect();
|
|
5631
|
+
this.pusher = null;
|
|
5632
|
+
}
|
|
5633
|
+
const options = {
|
|
5634
|
+
wsHost: sockets.url,
|
|
5635
|
+
wsPort: sockets.port,
|
|
5636
|
+
enabledTransports: ['wss', 'ws'],
|
|
5637
|
+
forceTLS: false,
|
|
5638
|
+
enableStats: false,
|
|
5639
|
+
};
|
|
5640
|
+
const { apiSecurityUrl } = this.environments;
|
|
5641
|
+
if (apiSecurityUrl) {
|
|
5642
|
+
this.refreshChannelAuthHeader();
|
|
5643
|
+
options.channelAuthorization = {
|
|
5644
|
+
transport: 'ajax',
|
|
5645
|
+
endpoint: `${apiSecurityUrl}${SOCKETS_AUTH_PATH}`,
|
|
5646
|
+
headers: this.channelAuthHeaders,
|
|
5647
|
+
headersProvider: () => {
|
|
5648
|
+
this.refreshChannelAuthHeader();
|
|
5649
|
+
return this.channelAuthHeaders;
|
|
5650
|
+
},
|
|
5651
|
+
};
|
|
5652
|
+
}
|
|
5653
|
+
const pusher = new Pusher(appKey, options);
|
|
5654
|
+
if (sockets.debug) {
|
|
5655
|
+
Pusher.logToConsole = true;
|
|
5656
|
+
}
|
|
5594
5657
|
this.pusher = pusher;
|
|
5658
|
+
return resolve(pusher);
|
|
5595
5659
|
});
|
|
5596
5660
|
}
|
|
5597
5661
|
/**
|
|
@@ -5614,13 +5678,16 @@ class WebSocketsService {
|
|
|
5614
5678
|
* @throws {Error} If the subscription fails after the maximum number of retry attempts.
|
|
5615
5679
|
*/
|
|
5616
5680
|
async channelSub(channelName) {
|
|
5681
|
+
const pusher = await this.ensureConnected();
|
|
5682
|
+
this.refreshChannelAuthHeader();
|
|
5617
5683
|
const attempts = 3;
|
|
5618
5684
|
for (let attempt = 0; attempt <= attempts; attempt++) {
|
|
5619
|
-
const channel =
|
|
5685
|
+
const channel = pusher.channel(channelName);
|
|
5620
5686
|
if (channel?.subscribed) {
|
|
5621
5687
|
return channel;
|
|
5622
5688
|
}
|
|
5623
|
-
this.
|
|
5689
|
+
this.refreshChannelAuthHeader();
|
|
5690
|
+
pusher.subscribe(channelName);
|
|
5624
5691
|
if (attempt < attempts) {
|
|
5625
5692
|
await this.wait();
|
|
5626
5693
|
}
|
|
@@ -5637,13 +5704,22 @@ class WebSocketsService {
|
|
|
5637
5704
|
*/
|
|
5638
5705
|
eventBind(channel, event) {
|
|
5639
5706
|
return new Observable((subscriber) => {
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5707
|
+
void (async () => {
|
|
5708
|
+
try {
|
|
5709
|
+
const pusher = await this.ensureConnected();
|
|
5710
|
+
this.refreshChannelAuthHeader();
|
|
5711
|
+
if (channel?.name) {
|
|
5712
|
+
channel.bind(event, (data) => subscriber.next(data));
|
|
5713
|
+
}
|
|
5714
|
+
else {
|
|
5715
|
+
pusher.subscribe(channel)
|
|
5716
|
+
.bind(event, (data) => subscriber.next(data));
|
|
5717
|
+
}
|
|
5718
|
+
}
|
|
5719
|
+
catch (error) {
|
|
5720
|
+
subscriber.error(error);
|
|
5721
|
+
}
|
|
5722
|
+
})();
|
|
5647
5723
|
});
|
|
5648
5724
|
}
|
|
5649
5725
|
/**
|
|
@@ -5657,23 +5733,33 @@ class WebSocketsService {
|
|
|
5657
5733
|
eventUnbind(channel, event) {
|
|
5658
5734
|
return new Observable((subscriber) => channel.unbind(event, (data) => subscriber.next(data)));
|
|
5659
5735
|
}
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
});
|
|
5672
|
-
if (sockets.debug) {
|
|
5673
|
-
Pusher.logToConsole = true;
|
|
5736
|
+
async ensureConnected() {
|
|
5737
|
+
if (this.pusher)
|
|
5738
|
+
return this.pusher;
|
|
5739
|
+
if (!this.appKey) {
|
|
5740
|
+
throw new Error('The sockets connection is not established.');
|
|
5741
|
+
}
|
|
5742
|
+
this.connectPromise ??= this.connect(this.appKey);
|
|
5743
|
+
try {
|
|
5744
|
+
const pusher = await this.connectPromise;
|
|
5745
|
+
if (!pusher) {
|
|
5746
|
+
throw new Error('The sockets connection is not established.');
|
|
5674
5747
|
}
|
|
5675
|
-
return
|
|
5676
|
-
}
|
|
5748
|
+
return pusher;
|
|
5749
|
+
}
|
|
5750
|
+
catch (error) {
|
|
5751
|
+
this.connectPromise = null;
|
|
5752
|
+
throw error;
|
|
5753
|
+
}
|
|
5754
|
+
}
|
|
5755
|
+
refreshChannelAuthHeader() {
|
|
5756
|
+
const token = this.getAuthToken?.() ?? null;
|
|
5757
|
+
if (token) {
|
|
5758
|
+
this.channelAuthHeaders['Authorization'] = `Bearer ${token}`;
|
|
5759
|
+
}
|
|
5760
|
+
else {
|
|
5761
|
+
delete this.channelAuthHeaders['Authorization'];
|
|
5762
|
+
}
|
|
5677
5763
|
}
|
|
5678
5764
|
async wait() {
|
|
5679
5765
|
const waitTime = 3 * 1000;
|
|
@@ -5687,13 +5773,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
5687
5773
|
args: [{
|
|
5688
5774
|
providedIn: 'root',
|
|
5689
5775
|
}]
|
|
5690
|
-
}]
|
|
5776
|
+
}] });
|
|
5691
5777
|
|
|
5692
5778
|
const AES_KEY_USAGES = ['encrypt', 'decrypt'];
|
|
5693
5779
|
class CryptoService {
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
const cryptoKey = await this.loadKey();
|
|
5780
|
+
async encryptAES(plaintext, secretKey) {
|
|
5781
|
+
const cryptoKey = await this.loadKey(secretKey);
|
|
5697
5782
|
// Convert the plaintext in Uint8Array
|
|
5698
5783
|
const encoder = new TextEncoder();
|
|
5699
5784
|
const encoded = encoder.encode(plaintext);
|
|
@@ -5706,13 +5791,13 @@ class CryptoService {
|
|
|
5706
5791
|
}, cryptoKey, encoded);
|
|
5707
5792
|
return `${this.uint8ArrayToBase64(iv)}:${this.arrayBufferToBase64(ciphertext)}`;
|
|
5708
5793
|
}
|
|
5709
|
-
async decryptAES(payload) {
|
|
5794
|
+
async decryptAES(payload, secretKey) {
|
|
5710
5795
|
// Extract the Initialization Vector (IV), and the cypher text
|
|
5711
5796
|
const [base64IV, base64Ciphertext] = payload.split(':');
|
|
5712
5797
|
if (!base64IV || !base64Ciphertext) {
|
|
5713
5798
|
throw new Error('The payload must contain the IV and the cipher text.');
|
|
5714
5799
|
}
|
|
5715
|
-
const cryptoKey = await this.loadKey();
|
|
5800
|
+
const cryptoKey = await this.loadKey(secretKey);
|
|
5716
5801
|
const iv = this.base64ToUint8Array(base64IV);
|
|
5717
5802
|
const cipherText = this.base64ToArrayBuffer(base64Ciphertext);
|
|
5718
5803
|
// Decrypt the cypher text
|
|
@@ -5724,14 +5809,12 @@ class CryptoService {
|
|
|
5724
5809
|
const decoder = new TextDecoder();
|
|
5725
5810
|
return decoder.decode(decrypted);
|
|
5726
5811
|
}
|
|
5727
|
-
async loadKey() {
|
|
5728
|
-
if (!
|
|
5729
|
-
throw new Error('The secret key is not defined
|
|
5812
|
+
async loadKey(secretKey) {
|
|
5813
|
+
if (!secretKey) {
|
|
5814
|
+
throw new Error('The secret key is not defined.');
|
|
5730
5815
|
}
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
// Import the key to API Crypto
|
|
5734
|
-
return await crypto.subtle.importKey('raw', rawKey, { name: 'AES-GCM' }, true, AES_KEY_USAGES);
|
|
5816
|
+
const rawKey = new TextEncoder().encode(secretKey);
|
|
5817
|
+
return crypto.subtle.importKey('raw', rawKey, { name: 'AES-GCM' }, true, AES_KEY_USAGES);
|
|
5735
5818
|
}
|
|
5736
5819
|
uint8ArrayToBase64(data) {
|
|
5737
5820
|
let binary = '';
|