Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(xapi): add support for Basic auth via meta_secret-lrs-payload #47

Merged
merged 3 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ jobs:
context: .
platforms: linux/amd64
cache-from: type=registry,ref=${{ steps.tag.outputs.IMAGE }}
cache-to: type=registry,ref=${{ steps.tag.outputs.IMAGE }},image-manifest=true,oci-mediatypes=true,mode=max
labels: |
${{ steps.meta.outputs.labels }}

Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

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
* fix: remove cache-to from image push to make dockerhub images usable
* build: [email protected]

### v3.1.0

* feat(events): add guest field to user-joined/user-left
Expand Down
57 changes: 9 additions & 48 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"dependencies": {
"bullmq": "4.17.0",
"config": "^3.3.7",
"express": "^4.18.2",
"express": "^4.19.2",
"js-yaml": "^4.1.0",
"luxon": "^3.4.3",
"node-fetch": "^3.3.2",
Expand Down
30 changes: 22 additions & 8 deletions src/out/xapi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 23 additions & 9 deletions src/out/xapi/xapi.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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",
Expand Down Expand Up @@ -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
Expand Down
Loading