npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@dinoboff/ims-lti

v3.1.0-rc7

Published

Module for building an LTI Tool Provider and accept LTI launch requests

Downloads

214

Readme

@dinoboff/ims-lti

This is a nodejs library used to help create Tool Providers for the IMS LTI standard. Tool Consumer implmentation is left as an excersise to the reader :P

Install

npm install ims-lti --save

To require the library into your project

require '@dinoboff/ims-lti'

Supported LTI Versions

Usage

The LTI standard won't be covered here, but it would be good to familiarize yourself with the specs. LTI documentation

This library doesn't help you manage or distribute the consumer keys and secrets. The POST parameters will contain the oauth_consumer_key and your application should use that to look up the consumer secret from your own datastore.

This library offers a few interfaces to use for managing the OAuth nonces to make sure the same nonce isn't used twice with the same timestamp. Read the LTI documentation on OAuth. They will be covered below.

Setting up a Tool Provider (TP)

As a TP your app will receive a POST request with LTI launch data that will be signed with OAuth using a key/secret that both the TP and Tool Consumer (TC) share. This is all covered in the LTI security model

Once you find the oauth_consumer_secret based on the oauth_consumer_key in the POST request, you can initialize a Provider object with them and a few other optional parameters:

lti = require '@dinoboff/ims-lti'
hmac = require '@dinoboff/ims-lti/lib/hmac-sha1'

provider = new lti.Provider consumer_key, consumer_secret

# To use x-forwarded-* headers
provider = new lti.Provider consumer_key, consumer_secret, trustProxy: true

# To provide the nonce store
store = new lti.Stores.MemoryStore
provider = new lti.Provider consumer_key, consumer_secret, nonceStore: store

# To provide the signer
sig = new hmac.HMAC_SHA1 trustProxy: false
provider = new lti.Provider consumer_key, consumer_secret, signer: sig

Once the provider has been initialized, a reqest object can be validated against it. During validation, OAuth signatures are checked against the passed consumer_secret and signautre_method ( HMAC_SHA1 assumed ). isValid returns true if the request is an lti request and is properly signed.

provider.valid_request req, (err, isValid) ->
  # isValid = Boolean | always false if err
  # err = Error object with method descibing error if err, null if no error

After validating the reqest, the provider object both stores the requests parameters (excluding oauth parameters) and provides convinience accessors to common onces including provider.student, provider.ta, provider.username, and more. All request data can be accessed through provider.body in an effort to namespace the values.

Currently there is not an emplementation for posting back to the Tool Consumer, although there is a boolean accessor provider.outcome_service that will return true if the TC will accept a POSTback.

Nonce Stores

@dinoboff/ims-lti does not standardize the way in which the OAuth nonce/timestamp is to be stored. Since it is a crutial part of OAuth security, this library implements an Interface to allow the user to implement their own nonce-stores.

Nonce Interface

All custom Nonce stores should extend the NonceStore class and implment isNew and setUsed

class NonceStore
  isNew:   (nonce,timestamp,callback)=>
    # Sets any new nonce to used
  setUsed: (nonce,timestamp,callback)=>

Two nonce stores have been implemented for convinience.

MemoryNonceStore

The default nonce store (if none is specified) is the Memory Nonce Store. This store simply keeps an array of nocne/timestamp keys. Timestamps must be valid within a 5 minute grace period.

RedisNonceStore

A superior nonce store is the RedisNonceStore. This store requires a secondary input into the constructor, a redis-client. The redis client is used to store the nonce keys and set them to expire within a set amount of time (default 5 minutes). A RedisNonceStore is initialized like:

RedisNonceStore = require '../lib/redis-nonce-store'
client          = require('redis').createClient()
store           = new RedisNonceStore('consumer_key', client)

provider = new lti.Provider consumer_key, consumer_secret, store

Outcomes Extension

The outcomes feature is part of the LTI 1.1 specification and is new to @dinoboff/ims-lti 1.0. All of the behind-the-scenes work necessary to get the ball rolling with it is already implemented for you, all you need to do is submit grades.

provider = new lti.Provider consumer_key, consumer_secret

provider.valid_request req, (err, is_valid) ->
  # Check if the request is valid and if the outcomes service exists.
  if (!is_valid || !provider.outcome_service) return false

  # Check if the outcome service supports the result data extension using the
  # text format. Available formats include text and url.
  console.log provider.outcome_service.supports_result_data('text')

  # Replace accepts a value between 0 and 1.
  provider.outcome_service.send_replace_result .5, (err, result) ->
    console.log result # True or false

  provider.outcome_service.send_read_result (err, result) ->
    console.log result # Value of the result already submitted from this embed

  provider.outcome_service.send_delete_result (err, result) ->
    console.log result # True or false

  provider.outcome_service.send_replace_result_with_text .5, 'Hello, world!', (err, result) ->
    console.log result # True or false

  provider.outcome_service.send_replace_result_with_url .5, 'https://google.com', (err, result) ->
    console.log result # True or false

Content Extension

The content extension is an extension supported by most LMS platforms. It provides LTI providers a way to send content back to the LMS in the form of urls, images, files, oembeds, iframes, and even lti launch urls.

provider = new lti.Provider consumer_key, consumer_secret

provider.valid_request req, (err, is_valid) ->
  #check if the request is valid and if the content extension is loaded.
  if (!is_valid || !provider.ext_content) return false

  provider.ext_content.has_return_type 'file' # Does the consumer support files
  provider.ext_content.has_file_extension 'jpg' # Does the consumer support jpg

  # All send requests take a response object as the first parameter. How the
  # response object is manipulated can be overrided by replacing
  # lti.Extensions.Content.redirector with your own function that accepts two
  # parameters, the response object and the url to redirect to.
  provider.ext_content.send_file res, file_url, text, content_mime_type

  provider.ext_content.send_iframe res, iframe_url, title_attribute, width, height

  provider.ext_content.send_image_url res, image_url, text, width, height

  provider.ext_content.send_lti_launch_url res, launch_url, title_attribute, text

  provider.ext_content.send_oembed res, oembed_url, endpoint

  provider.ext_content.send_url res, hyperlink_url, text, title_attribute, target_attribute

Running Tests

To run the test suite first installing the dependencies:

npm install
make test