Create LTI Consumer for Moodle

39 Views Asked by At

I tried to create LTI Consumer using Node.JS and html , JS .

when I click the button I get the request params from the nodejs with the signature , and call to moodle , and I got 302 found with the location of the return URL with eror :

https://DOMAIN/lti?lti_errormsg=Sorry%2C+there+was+an+error+connecting+you+to+the+application.&lti_errorlog=Debug+error%3A+OAuth+signature+check+failed+-+perhaps+an+incorrect+secret+or+timestamp.

what wrong with my signature ?

this is my nodejs index.js :


const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const btoa = require('btoa');
const md5 = require('md5');
const app = express();
app.use(express.static(path.join(__dirname, 'public')));

  
  

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

const PORT = process.env.PORT || 3030;

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});


app.get('/' , (req, res)=>{
    res.sendFile(path.join(__dirname, 'public', 'index.html'));

})


app.get('/lti' , (req, res)=>{
res.sendFile(path.join(__dirname , 'public' , 'lti.html'));
})


function generateNonce() {
    const mt = String(new Date().getTime() / 1000);
    const rand = String(Math.floor(Math.random() * 1000000));

    return md5(mt + rand); // You would need an md5 function here, possibly from a library or implementation
}

app.get('/sign' , (req , res)=>{


var oauth = require('oauth-sign');
var action = 'https://DOMAIN/enrol/lti/tool.php?id=2';
var method = 'POST';
var timestamp = Math.floor(Date.now() / 1000);
console.log(timestamp);


var basicParams = {
    // LTI Required Parameters
    // OAuth 1.0a Required Parameters
    oauth_nonce: generateNonce(),
    oauth_signature_method: 'HMAC-SHA1',
    oauth_timestamp: timestamp,
oauth_version: '1.0',
oauth_consumer_key: 'BBBB',
resource_link_id: '1',
lti_message_type: 'basic-lti-launch-request',
lti_version: 'LTI-1p0',
launch_presentation_return_url: 'https://DOMAIN/lti',
roles: 'Instructor,urn:lti:sysrole:ims/lis/Administrator,urn:lti:instrole:ims/lis/Administrator',
context_id: '2',
context_label: 'aaa',
context_title: 'aaa from moodle',
resource_link_title: 'aaa',
resource_link_description: 'a',
context_type: 'CourseSection',
launch_presentation_locale: 'en',
tool_consumer_info_product_family_code: 'moodle',
tool_consumer_info_version: '2023100900',
oauth_callback: 'about:blank',
tool_consumer_instance_name: 'New Site',
tool_consumer_instance_description: 'New Site',
lis_person_sourcedid: '',
user_id: '2',
tool_consumer_instance_guid: 'dd1bd87b4dc23b9665f4696523508c92',
launch_presentation_document_target: 'window',
lis_course_section_sourcedid: '',
ext_lms: 'moodle-2'
};




let secret = 'SECRET';
var signature = oauth.hmacsign(method, action, basicParams, secret , '' );
basicParams.oauth_signature = signature;

console.log(basicParams);

res.json(basicParams);

})

and this is the index.html :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>LTI Request Example</title>
   </head>
<body>


    <pre><code class="language-json"></code></pre>
    <form id="ltiForm"></form>
    <button type="submit" id="submitBtn" form="ltiForm">POST to LTI Tool Provider!</button>

<iframe id="resultFrame" width="600" height="400" frameborder="0"></iframe>

<script>


async function makeLTILaunchRequest() {
   
let sign = await fetch('/sign');
let params = await sign.json();

     var action = 'https://DOMAIN/enrol/lti/tool.php?id=2';
 var method = 'POST';


    var form = document.querySelector("#ltiForm");
        form.action = action;
        form.method = method;
        for (var name in params) {
            var node = document.createElement("input");
            node.name = name;
            node.type = 'hidden';
            node.value = params[name];
            form.appendChild(node);
        }


        var output = document.querySelector("code");
        output.textContent = JSON.stringify(params, null, 2);
        console.log(form);

        var meta = document.querySelector("body > script");
        console.log(meta);
}


makeLTILaunchRequest();
</script>

</body>
</html>


0

There are 0 best solutions below