@experteam-mx/ngx-services 20.9.10 → 20.9.11
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.
|
@@ -5912,16 +5912,80 @@ var CustomerRoleType;
|
|
|
5912
5912
|
CustomerRoleType["EXPORTER"] = "EP";
|
|
5913
5913
|
})(CustomerRoleType || (CustomerRoleType = {}));
|
|
5914
5914
|
|
|
5915
|
+
const SOCKETS_AUTH_PATH = '/sockets/auth';
|
|
5915
5916
|
class WebSocketsService {
|
|
5916
|
-
pusher;
|
|
5917
|
+
pusher = null;
|
|
5918
|
+
appKey = null;
|
|
5919
|
+
connectPromise = null;
|
|
5917
5920
|
environments = inject(ENVIRONMENT_TOKEN);
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
|
|
5922
|
-
|
|
5923
|
-
|
|
5921
|
+
getAuthToken = null;
|
|
5922
|
+
channelAuthHeaders = {};
|
|
5923
|
+
/**
|
|
5924
|
+
* Stores the Pusher/Soketi application key without opening a connection.
|
|
5925
|
+
* The first `channelSub` / `eventBind` opens Pusher via `ensureConnected`.
|
|
5926
|
+
*
|
|
5927
|
+
* @param {string} appKey - The Pusher/Soketi application key.
|
|
5928
|
+
*/
|
|
5929
|
+
setAppKey(appKey) {
|
|
5930
|
+
this.appKey = appKey;
|
|
5931
|
+
}
|
|
5932
|
+
/**
|
|
5933
|
+
* Registers a live token provider used when authorizing private/presence channels.
|
|
5934
|
+
* The provider is called at subscribe/authorize time; the token is not snapshotted here.
|
|
5935
|
+
*
|
|
5936
|
+
* @param {() => string | null} getToken - Returns the current session token, or null.
|
|
5937
|
+
*/
|
|
5938
|
+
setAuthTokenProvider(getToken) {
|
|
5939
|
+
this.getAuthToken = getToken;
|
|
5940
|
+
}
|
|
5941
|
+
/**
|
|
5942
|
+
* Connects to Pusher using the given app key and env `sockets` url/port/debug.
|
|
5943
|
+
* No-ops if already connected with the same key; reconnects if the key changed.
|
|
5944
|
+
* Resolves false when `sockets` is missing from the environment.
|
|
5945
|
+
* Apps should store the key with `setAppKey` and let subscribe open the client.
|
|
5946
|
+
*
|
|
5947
|
+
* @param {string} appKey - The Pusher/Soketi application key.
|
|
5948
|
+
* @return {Promise<Pusher | false>} The Pusher instance, or false when sockets are not configured.
|
|
5949
|
+
*/
|
|
5950
|
+
connect(appKey) {
|
|
5951
|
+
this.setAppKey(appKey);
|
|
5952
|
+
return new Promise((resolve) => {
|
|
5953
|
+
if (this.pusher && this.appKey === appKey) {
|
|
5954
|
+
return resolve(this.pusher);
|
|
5955
|
+
}
|
|
5956
|
+
const { sockets } = this.environments;
|
|
5957
|
+
if (!sockets)
|
|
5958
|
+
return resolve(false);
|
|
5959
|
+
if (this.pusher) {
|
|
5960
|
+
this.pusher.disconnect();
|
|
5961
|
+
this.pusher = null;
|
|
5962
|
+
}
|
|
5963
|
+
const options = {
|
|
5964
|
+
wsHost: sockets.url,
|
|
5965
|
+
wsPort: sockets.port,
|
|
5966
|
+
enabledTransports: ['wss', 'ws'],
|
|
5967
|
+
forceTLS: false,
|
|
5968
|
+
enableStats: false,
|
|
5969
|
+
};
|
|
5970
|
+
const { apiSecurityUrl } = this.environments;
|
|
5971
|
+
if (apiSecurityUrl) {
|
|
5972
|
+
this.refreshChannelAuthHeader();
|
|
5973
|
+
options.channelAuthorization = {
|
|
5974
|
+
transport: 'ajax',
|
|
5975
|
+
endpoint: `${apiSecurityUrl}${SOCKETS_AUTH_PATH}`,
|
|
5976
|
+
headers: this.channelAuthHeaders,
|
|
5977
|
+
headersProvider: () => {
|
|
5978
|
+
this.refreshChannelAuthHeader();
|
|
5979
|
+
return this.channelAuthHeaders;
|
|
5980
|
+
},
|
|
5981
|
+
};
|
|
5982
|
+
}
|
|
5983
|
+
const pusher = new Pusher(appKey, options);
|
|
5984
|
+
if (sockets.debug) {
|
|
5985
|
+
Pusher.logToConsole = true;
|
|
5986
|
+
}
|
|
5924
5987
|
this.pusher = pusher;
|
|
5988
|
+
return resolve(pusher);
|
|
5925
5989
|
});
|
|
5926
5990
|
}
|
|
5927
5991
|
/**
|
|
@@ -5937,25 +6001,40 @@ class WebSocketsService {
|
|
|
5937
6001
|
return channel.trigger(`client-${eventName}`, data);
|
|
5938
6002
|
}
|
|
5939
6003
|
/**
|
|
5940
|
-
* Subscribes to a specified channel
|
|
6004
|
+
* Subscribes to a specified channel and resolves when Pusher reports success.
|
|
5941
6005
|
*
|
|
5942
6006
|
* @param {string} channelName - The name of the channel to be subscribed to.
|
|
5943
6007
|
* @return {Promise<Channel>} A promise that resolves to the subscribed channel object if successful.
|
|
5944
|
-
* @throws {Error} If the subscription fails
|
|
6008
|
+
* @throws {Error} If the subscription fails.
|
|
5945
6009
|
*/
|
|
5946
6010
|
async channelSub(channelName) {
|
|
5947
|
-
const
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
}
|
|
5953
|
-
this.pusher?.subscribe(channelName);
|
|
5954
|
-
if (attempt < attempts) {
|
|
5955
|
-
await this.wait();
|
|
5956
|
-
}
|
|
6011
|
+
const pusher = await this.ensureConnected();
|
|
6012
|
+
this.refreshChannelAuthHeader();
|
|
6013
|
+
const existing = pusher.channel(channelName);
|
|
6014
|
+
if (existing?.subscribed) {
|
|
6015
|
+
return existing;
|
|
5957
6016
|
}
|
|
5958
|
-
|
|
6017
|
+
const channel = pusher.subscribe(channelName);
|
|
6018
|
+
if (channel.subscribed) {
|
|
6019
|
+
return channel;
|
|
6020
|
+
}
|
|
6021
|
+
await new Promise((resolve, reject) => {
|
|
6022
|
+
const onSuccess = () => {
|
|
6023
|
+
cleanup();
|
|
6024
|
+
resolve();
|
|
6025
|
+
};
|
|
6026
|
+
const onError = () => {
|
|
6027
|
+
cleanup();
|
|
6028
|
+
reject(new Error(`Failed to subscribe to channel "${channelName}".`));
|
|
6029
|
+
};
|
|
6030
|
+
const cleanup = () => {
|
|
6031
|
+
channel.unbind('pusher:subscription_succeeded', onSuccess);
|
|
6032
|
+
channel.unbind('pusher:subscription_error', onError);
|
|
6033
|
+
};
|
|
6034
|
+
channel.bind('pusher:subscription_succeeded', onSuccess);
|
|
6035
|
+
channel.bind('pusher:subscription_error', onError);
|
|
6036
|
+
});
|
|
6037
|
+
return channel;
|
|
5959
6038
|
}
|
|
5960
6039
|
/**
|
|
5961
6040
|
* Binds an event listener to a specified event on a given channel using Pusher or a Channel object,
|
|
@@ -5969,11 +6048,19 @@ class WebSocketsService {
|
|
|
5969
6048
|
return new Observable((subscriber) => {
|
|
5970
6049
|
if (channel?.name) {
|
|
5971
6050
|
channel.bind(event, (data) => subscriber.next(data));
|
|
6051
|
+
return;
|
|
5972
6052
|
}
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
6053
|
+
void (async () => {
|
|
6054
|
+
try {
|
|
6055
|
+
const pusher = await this.ensureConnected();
|
|
6056
|
+
this.refreshChannelAuthHeader();
|
|
6057
|
+
pusher.subscribe(channel)
|
|
6058
|
+
.bind(event, (data) => subscriber.next(data));
|
|
6059
|
+
}
|
|
6060
|
+
catch (error) {
|
|
6061
|
+
subscriber.error(error);
|
|
6062
|
+
}
|
|
6063
|
+
})();
|
|
5977
6064
|
});
|
|
5978
6065
|
}
|
|
5979
6066
|
/**
|
|
@@ -5987,27 +6074,41 @@ class WebSocketsService {
|
|
|
5987
6074
|
eventUnbind(channel, event) {
|
|
5988
6075
|
return new Observable((subscriber) => channel.unbind(event, (data) => subscriber.next(data)));
|
|
5989
6076
|
}
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6077
|
+
/**
|
|
6078
|
+
* Unsubscribes from a channel by name.
|
|
6079
|
+
*
|
|
6080
|
+
* @param {string} channelName - The channel name previously passed to subscribe.
|
|
6081
|
+
*/
|
|
6082
|
+
unsubscribe(channelName) {
|
|
6083
|
+
this.pusher?.unsubscribe(channelName);
|
|
6084
|
+
}
|
|
6085
|
+
async ensureConnected() {
|
|
6086
|
+
if (this.pusher)
|
|
6087
|
+
return this.pusher;
|
|
6088
|
+
if (!this.appKey) {
|
|
6089
|
+
throw new Error('The sockets connection is not established.');
|
|
6090
|
+
}
|
|
6091
|
+
this.connectPromise ??= this.connect(this.appKey);
|
|
6092
|
+
try {
|
|
6093
|
+
const pusher = await this.connectPromise;
|
|
6094
|
+
if (!pusher) {
|
|
6095
|
+
throw new Error('The sockets connection is not established.');
|
|
6004
6096
|
}
|
|
6005
|
-
return
|
|
6006
|
-
}
|
|
6097
|
+
return pusher;
|
|
6098
|
+
}
|
|
6099
|
+
catch (error) {
|
|
6100
|
+
this.connectPromise = null;
|
|
6101
|
+
throw error;
|
|
6102
|
+
}
|
|
6007
6103
|
}
|
|
6008
|
-
|
|
6009
|
-
const
|
|
6010
|
-
|
|
6104
|
+
refreshChannelAuthHeader() {
|
|
6105
|
+
const token = this.getAuthToken?.() ?? null;
|
|
6106
|
+
if (token) {
|
|
6107
|
+
this.channelAuthHeaders['Authorization'] = `Bearer ${token}`;
|
|
6108
|
+
}
|
|
6109
|
+
else {
|
|
6110
|
+
delete this.channelAuthHeaders['Authorization'];
|
|
6111
|
+
}
|
|
6011
6112
|
}
|
|
6012
6113
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: WebSocketsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
6013
6114
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: WebSocketsService, providedIn: 'root' });
|
|
@@ -6017,13 +6118,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
|
|
|
6017
6118
|
args: [{
|
|
6018
6119
|
providedIn: 'root',
|
|
6019
6120
|
}]
|
|
6020
|
-
}]
|
|
6121
|
+
}] });
|
|
6021
6122
|
|
|
6022
6123
|
const AES_KEY_USAGES = ['encrypt', 'decrypt'];
|
|
6023
6124
|
class CryptoService {
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
const cryptoKey = await this.loadKey();
|
|
6125
|
+
async encryptAES(plaintext, secretKey) {
|
|
6126
|
+
const cryptoKey = await this.loadKey(secretKey);
|
|
6027
6127
|
// Convert the plaintext in Uint8Array
|
|
6028
6128
|
const encoder = new TextEncoder();
|
|
6029
6129
|
const encoded = encoder.encode(plaintext);
|
|
@@ -6036,13 +6136,13 @@ class CryptoService {
|
|
|
6036
6136
|
}, cryptoKey, encoded);
|
|
6037
6137
|
return `${this.uint8ArrayToBase64(iv)}:${this.arrayBufferToBase64(ciphertext)}`;
|
|
6038
6138
|
}
|
|
6039
|
-
async decryptAES(payload) {
|
|
6139
|
+
async decryptAES(payload, secretKey) {
|
|
6040
6140
|
// Extract the Initialization Vector (IV), and the cypher text
|
|
6041
6141
|
const [base64IV, base64Ciphertext] = payload.split(':');
|
|
6042
6142
|
if (!base64IV || !base64Ciphertext) {
|
|
6043
6143
|
throw new Error('The payload must contain the IV and the cipher text.');
|
|
6044
6144
|
}
|
|
6045
|
-
const cryptoKey = await this.loadKey();
|
|
6145
|
+
const cryptoKey = await this.loadKey(secretKey);
|
|
6046
6146
|
const iv = this.base64ToUint8Array(base64IV);
|
|
6047
6147
|
const cipherText = this.base64ToArrayBuffer(base64Ciphertext);
|
|
6048
6148
|
// Decrypt the cypher text
|
|
@@ -6054,14 +6154,12 @@ class CryptoService {
|
|
|
6054
6154
|
const decoder = new TextDecoder();
|
|
6055
6155
|
return decoder.decode(decrypted);
|
|
6056
6156
|
}
|
|
6057
|
-
async loadKey() {
|
|
6058
|
-
if (!
|
|
6059
|
-
throw new Error('The secret key is not defined
|
|
6157
|
+
async loadKey(secretKey) {
|
|
6158
|
+
if (!secretKey) {
|
|
6159
|
+
throw new Error('The secret key is not defined.');
|
|
6060
6160
|
}
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
// Import the key to API Crypto
|
|
6064
|
-
return await crypto.subtle.importKey('raw', rawKey, { name: 'AES-GCM' }, true, AES_KEY_USAGES);
|
|
6161
|
+
const rawKey = new TextEncoder().encode(secretKey);
|
|
6162
|
+
return crypto.subtle.importKey('raw', rawKey, { name: 'AES-GCM' }, true, AES_KEY_USAGES);
|
|
6065
6163
|
}
|
|
6066
6164
|
uint8ArrayToBase64(data) {
|
|
6067
6165
|
let binary = '';
|