diff --git a/CHANGELOG.md b/CHANGELOG.md index db7f5dd..1089b43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. ### UNRELEASED +* feat(xapi): add support for Basic auth via meta_secret-lrs-payload * build: express@4.19.2 ### v3.1.0 diff --git a/src/out/xapi/README.md b/src/out/xapi/README.md index 6572c67..91e9406 100644 --- a/src/out/xapi/README.md +++ b/src/out/xapi/README.md @@ -64,14 +64,28 @@ If you set `meta_xapi-enabled` to false, no xAPI events will be generated or sen ### meta_secret-lrs-payload - **Description**: This parameter allows you to specify the credentials and endpoint of the Learning Record Store (LRS) where the xAPI events will be sent. The payload is a Base64-encoded string representing a JSON object encrypted (AES 256/PBKDF2) using the **server secret** as the **passphrase**. -- **Value Format**: Base64-encoded JSON object encrypted with AES 256/PBKDF2 encryption -- **JSON Payload Structure**: -```json -{ - "lrs_endpoint": "https://lrs1.example.com", - "lrs_token": "AAF32423SDF5345" -} -``` +There are two supported formats for the payload: + +- **LRS Token (Bearer authentication)** + - **Value Format**: Base64-encoded JSON object encrypted with AES 256/PBKDF2 encryption + - **JSON Payload Structure**: + ```json + { + "lrs_endpoint": "https://lrs1.example.com", + "lrs_token": "AAF32423SDF5345" + } + ``` +- **LRS Username/Password (Basic authentication)** + - **Value Format**: Base64-encoded JSON object encrypted with AES 256/PBKDF2 encryption + - **JSON Payload Structure**: + ```json + { + "lrs_endpoint": "https://lrs1.example.com", + "lrs_username": "user", + "lrs_password": "pass" + } + ``` + - **Encrypting the Payload**: The Payload should be encrypted with the server secret using the following bash command (provided the lrs credential are in the `lrs.conf` file and server secret is `bab3fd92bcd7d464`): ```bash cat ./lrs.conf | openssl aes-256-cbc -pass "pass:bab3fd92bcd7d464" -pbkdf2 -a -A diff --git a/src/out/xapi/xapi.js b/src/out/xapi/xapi.js index ee161d0..0f8912d 100644 --- a/src/out/xapi/xapi.js +++ b/src/out/xapi/xapi.js @@ -39,10 +39,9 @@ export default class XAPI { } async postToLRS(statement, meeting_data) { - let { lrs_endpoint, lrs_username, lrs_password } = this.config.lrs; - if (meeting_data.lrs_endpoint !== ''){ - lrs_endpoint = meeting_data.lrs_endpoint; - } + const lrs_username = meeting_data.lrs_username || this.config.lrs?.lrs_username; + const lrs_password = meeting_data.lrs_password || this.config.lrs?.lrs_password; + const lrs_endpoint = meeting_data.lrs_endpoint || this.config.lrs?.lrs_endpoint; const lrs_token = meeting_data.lrs_token; const headers = { Authorization: `Basic ${Buffer.from( @@ -52,9 +51,7 @@ export default class XAPI { "X-Experience-API-Version": "1.0.0", }; - if (lrs_token !== ''){ - headers.Authorization = `Bearer ${lrs_token}` - } + if (lrs_token) headers.Authorization = `Bearer ${lrs_token}` const requestOptions = { method: "POST", @@ -107,15 +104,32 @@ export default class XAPI { const lrs_payload = event.data.attributes.meeting.metadata?.["secret-lrs-payload"]; let lrs_endpoint = ''; let lrs_token = ''; + let lrs_username = ''; + let lrs_password = ''; // if lrs_payload exists, decrypts with the server secret and extracts lrs_endpoint and lrs_token from it if (lrs_payload !== undefined){ - const payload_text = decryptStr(lrs_payload, this.config.server.secret); - ({lrs_endpoint, lrs_token} = JSON.parse(payload_text)); + try { + const payload_text = decryptStr(lrs_payload, this.config.server.secret); + ({ + lrs_endpoint, + lrs_token, + lrs_username, + lrs_password, + } = JSON.parse(payload_text)); + } catch (error) { + this.logger.error("OutXAPI.onEvent: invalid lrs_payload", { + error: error.stack, + lrs_payload + }); + return reject(error); + } } meeting_data.lrs_endpoint = lrs_endpoint; meeting_data.lrs_token = lrs_token; + meeting_data.lrs_username = lrs_username; + meeting_data.lrs_password = lrs_password; const meeting_create_day = DateTime.fromMillis( meeting_data.create_time