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

Outcome service bug fix and other changes #45

Closed
wants to merge 5 commits into from
Closed
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
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -*- mode: ini-generic -*-

root = true

[*]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
43 changes: 29 additions & 14 deletions src/extensions/outcomes.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ xml2js = require 'xml2js'
xml_builder = require 'xmlbuilder'

errors = require '../errors'
HMAC_SHA1 = require '../hmac-sha1'
utils = require '../utils'


Expand Down Expand Up @@ -81,13 +82,15 @@ class OutcomeService
REQUEST_READ: 'readResult'
REQUEST_DELETE: 'deleteResult'


constructor: (@provider, @language = 'en') ->
body = @provider.body

@service_url = body.lis_outcome_service_url
@source_did = body.lis_result_sourcedid
@result_data_types = body.ext_outcome_data_values_accepted and body.ext_outcome_data_values_accepted.split(',') or []
constructor: (options = {}) ->
@consumer_key = options.consumer_key
@consumer_secret = options.consumer_secret
@service_url = options.service_url
@source_did = options.source_did
@result_data_types = options.result_data_types or []
@signer = options.signer or (new HMAC_SHA1())
@cert_authority = options.cert_authority or null
@language = options.language or 'en'

# Break apart the service url into the url fragments for use by OAuth signing, additionally prepare the OAuth
# specific url that used exclusively in the signing process.
Expand Down Expand Up @@ -125,7 +128,7 @@ class OutcomeService
@_send_request doc, callback
catch err
callback err, false


send_read_result: (callback) ->
doc = new OutcomeDocument @REQUEST_READ, @source_did, @
Expand All @@ -151,21 +154,25 @@ class OutcomeService

_send_request: (doc, callback) ->
xml = doc.finalize()
body = ''
body = ''
is_ssl = @service_url_parts.protocol == 'https:'

options =
hostname: @service_url_parts.hostname
agent: if is_ssl then https.globalAgent else http.globalAgent
path: @service_url_parts.path
method: 'POST'
headers: @_build_headers xml

if @cert_authority and is_ssl
options.ca = @cert_authority
else
options.agent = if is_ssl then https.globalAgent else http.globalAgent

if @service_url_parts.port
options.port = @service_url_parts.port

# Make the request to the TC, verifying that the status code is valid and fetching the entire response body.
req = http.request options, (res) =>
req = (if is_ssl then https else http).request options, (res) =>
res.setEncoding 'utf8'
res.on 'data', (chunk) => body += chunk
res.on 'end', () =>
Expand All @@ -186,11 +193,11 @@ class OutcomeService
oauth_version: '1.0'
oauth_nonce: uuid.v4()
oauth_timestamp: Math.round Date.now() / 1000
oauth_consumer_key: @provider.consumer_key
oauth_consumer_key: @consumer_key
oauth_body_hash: crypto.createHash('sha1').update(body).digest('base64')
oauth_signature_method: 'HMAC-SHA1'

headers.oauth_signature = @provider.signer.build_signature_raw @service_url_oauth, @service_url_parts, 'POST', headers, @provider.consumer_secret
headers.oauth_signature = @signer.build_signature_raw @service_url_oauth, @service_url_parts, 'POST', headers, @consumer_secret

Authorization: 'OAuth realm="",' + ("#{key}=\"#{utils.special_encode(val)}\"" for key, val of headers).join ','
'Content-Type': 'application/xml'
Expand All @@ -215,7 +222,15 @@ exports.init = (provider) ->
if (provider.body.lis_outcome_service_url and provider.body.lis_result_sourcedid)
# The LTI 1.1 spec says that the language parameter is usually implied to be en, so the OutcomeService object
# defaults to en until the spec updates and says there's other possible format options.
provider.outcome_service = new OutcomeService provider
accepted_vals = provider.body.ext_outcome_data_values_accepted
provider.outcome_service = new OutcomeService(
consumer_key: provider.consumer_key
consumer_secret: provider.consumer_secret
service_url: provider.body.lis_outcome_service_url,
source_did: provider.body.lis_result_sourcedid,
result_data_types: accepted_vals and accepted_vals.split(',') or []
signer: provider.signer
)
else
provider.outcome_service = false

Expand Down