Skip to content

Commit

Permalink
Merge pull request #10 from vanilla/feature/2dot0
Browse files Browse the repository at this point in the history
Update jsConnect to 2.0
  • Loading branch information
linc authored May 23, 2017
2 parents e0a6064 + 5365e18 commit 8a036f0
Show file tree
Hide file tree
Showing 9 changed files with 436 additions and 32 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea
/vendor/
30 changes: 30 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
language: php

php:
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1
- hhvm

matrix:
allow_failures:
- php: hhvm
fast_finish: true

install:
- composer self-update
- |
if [[ ${TRAVIS_PHP_VERSION:0:2} == "7." ]]; then
composer require "phpunit/phpunit=~5.7"
else
if [[ ${TRAVIS_PHP_VERSION:0:3} == "5.6" ]]; then
composer require "phpunit/phpunit=~5"
else
composer require "phpunit/phpunit=~4.8"
fi
fi
script: ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover=coverage.clover
59 changes: 35 additions & 24 deletions functions.jsconnect.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
* This file contains the client code for Vanilla jsConnect single sign on.
*
* @author Todd Burry <todd@vanillaforums.com>
* @version 1.3
* @copyright Copyright 2008, 2009 Vanilla Forums Inc.
* @license http://www.opensource.org/licenses/gpl-2.0.php GPLv2
* @version 2.0
* @copyright 2008-2017 Vanilla Forums, Inc.
* @license GNU GPLv2 http://www.opensource.org/licenses/gpl-2.0.php
*/

define('JS_CONNECT_VERSION', '2');
define('JS_TIMEOUT', 24 * 60);

/**
Expand All @@ -30,27 +31,35 @@ function writeJsConnect($user, $request, $clientID, $secret, $secure = true) {
// Error checking.
if ($secure) {
// Check the client.
if (!isset($request['client_id'])) {
$error = array('error' => 'invalid_request', 'message' => 'The client_id parameter is missing.');
if (!isset($request['v'])) {
$error = array('error' => 'invalid_request', 'message' => 'Missing the v parameter.');
} elseif ($request['v'] !== JS_CONNECT_VERSION) {
$error = array('error' => 'invalid_request', 'message' => "Unsupported version {$request['v']}.");
} elseif (!isset($request['client_id'])) {
$error = array('error' => 'invalid_request', 'message' => 'Missing the client_id parameter.');
} elseif ($request['client_id'] != $clientID) {
$error = array('error' => 'invalid_client', 'message' => "Unknown client {$request['client_id']}.");
} elseif (!isset($request['timestamp']) && !isset($request['signature'])) {
} elseif (!isset($request['timestamp']) && !isset($request['sig'])) {
if (is_array($user) && count($user) > 0) {
// This isn't really an error, but we are just going to return public information when no signature is sent.
$error = array('name' => (string)@$user['name'], 'photourl' => @$user['photourl'], 'signedin' => true);
} else {
$error = array('name' => '', 'photourl' => '');
}
} elseif (!isset($request['timestamp']) || !is_numeric($request['timestamp'])) {
} elseif (!isset($request['timestamp']) || !ctype_digit($request['timestamp'])) {
$error = array('error' => 'invalid_request', 'message' => 'The timestamp parameter is missing or invalid.');
} elseif (!isset($request['signature'])) {
$error = array('error' => 'invalid_request', 'message' => 'Missing signature parameter.');
} elseif (($Diff = abs($request['timestamp'] - jsTimestamp())) > JS_TIMEOUT) {
} elseif (!isset($request['sig'])) {
$error = array('error' => 'invalid_request', 'message' => 'Missing the sig parameter.');
} // Make sure the timestamp hasn't timedout
elseif (abs($request['timestamp'] - JsTimestamp()) > JS_TIMEOUT) {
$error = array('error' => 'invalid_request', 'message' => 'The timestamp is invalid.');
} elseif (!isset($request['nonce'])) {
$error = array('error' => 'invalid_request', 'message' => 'Missing the nonce parameter.');
} elseif (!isset($request['ip'])) {
$error = array('error' => 'invalid_request', 'message' => 'Missing the ip parameter.');
} else {
// Make sure the timestamp hasn't timed out.
$signature = jsHash($request['timestamp'].$secret, $secure);
if ($signature != $request['signature']) {
$signature = jsHash($request['ip'].$request['nonce'].$request['timestamp'].$secret, $secure);
if ($signature != $request['sig']) {
$error = array('error' => 'access_denied', 'message' => 'Signature invalid.');
}
}
Expand All @@ -62,7 +71,10 @@ function writeJsConnect($user, $request, $clientID, $secret, $secure = true) {
if ($secure === null) {
$result = $user;
} else {
$user['ip'] = $request['ip'];
$user['nonce'] = $request['nonce'];
$result = signJsConnect($user, $clientID, $secret, $secure, true);
$result['v'] = JS_CONNECT_VERSION;
}
} else {
$result = array('name' => '', 'photourl' => '');
Expand All @@ -85,24 +97,24 @@ function writeJsConnect($user, $request, $clientID, $secret, $secure = true) {
* @param $secret
* @param $hashType
* @param bool $returnData
* @return mixed
* @return array|string
*/
function signJsConnect($data, $clientID, $secret, $hashType, $returnData = false) {
$data2 = array_change_key_case($data);
ksort($data2);
$normalizedData = array_change_key_case($data);
ksort($normalizedData);

foreach ($data2 as $key => $value) {
foreach ($normalizedData as $key => $value) {
if ($value === null) {
$data[$key] = '';
$normalizedData[$key] = '';
}
}

$string = http_build_query($data2, null, '&');
$signature = jsHash($string.$secret, $hashType);
$stringifiedData = http_build_query($normalizedData, null, '&');
$signature = jsHash($stringifiedData.$secret, $hashType);
if ($returnData) {
$data['client_id'] = $clientID;
$data['signature'] = $signature;
return $data;
$normalizedData['client_id'] = $clientID;
$normalizedData['sig'] = $signature;
return $normalizedData;
} else {
return $signature;
}
Expand All @@ -114,7 +126,6 @@ function signJsConnect($data, $clientID, $secret, $hashType, $returnData = false
* @param string $string The string to hash.
* @param string|bool $secure The hash algorithm to use. true means md5.
* @return string
* @since 1.1b
*/
function jsHash($string, $secure = true) {
if ($secure === true) {
Expand Down
16 changes: 8 additions & 8 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@
$user = array();

if ($signedIn) {
// CHANGE THESE FOUR LINES.
$user['uniqueid'] = '123';
$user['name'] = 'John PHP';
$user['email'] = 'john.php@anonymous.com';
$user['photourl'] = '';
// CHANGE THESE FOUR LINES.
$user['uniqueid'] = '123';
$user['name'] = 'John PHP';
$user['email'] = 'john.php@example.com';
$user['photourl'] = '';
}

// 4. Generate the jsConnect string.

// This should be true unless you are testing.
// This should be true unless you are testing.
// You can also use a hash name like md5, sha1 etc which must be the name as the connection settings in Vanilla.
$secure = true;
WriteJsConnect($user, $_GET, $clientID, $secret, $secure);
$secure = true;
writeJsConnect($user, $_GET, $clientID, $secret, $secure);
35 changes: 35 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="tests/phpunit.php"
>
<php>
<ini name="intl.default_locale" value="en"/>
<ini name="intl.error_level" value="0"/>
<ini name="memory_limit" value="-1"/>
<ini name="date.timezone" value="America/Montreal"/>
</php>

<testsuites>
<testsuite name="All">
<directory suffix="Test.php">./tests/</directory>
</testsuite>
</testsuites>

<filter>
<whitelist addUncoveredFilesFromWhitelist="false">
<file>functions.jsconnect.php</file>
<exclude>
<file>index.php</file>
</exclude>
</whitelist>
</filter>
</phpunit>
42 changes: 42 additions & 0 deletions tests/HashTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
/**
* @author Alexandre (DaazKu) Chouinard <alexandre.c@vanillaforums.com>
* @copyright 2009-2017 Vanilla Forums Inc.
* @license GNU GPLv2 http://www.opensource.org/licenses/gpl-2.0.php
*/

namespace JsConnect\Tests;

/**
* Unit tests hashing
*/
class HashTest extends \PHPUnit_Framework_TestCase {

/**
* Test {@link jsHash} with no $secure parameter.
*/
public function testHashDefault() {
$this->assertEquals(md5('hashMe'), jsHash('hashMe'));
}

/**
* Test {@link jsHash} with true as the $secure parameter.
*/
public function testHashSecureTrue() {
$this->assertEquals(md5('hashMe'), jsHash('hashMe', true));
}

/**
* Test {@link jsHash} with 'md5' as the $secure parameter.
*/
public function testHashSecureMD5() {
$this->assertEquals(md5('hashMe'), jsHash('hashMe', 'md5'));
}

/**
* Test {@link jsHash} with 'sha256' as the $secure parameter.
*/
public function testHashSecureSHA256() {
$this->assertEquals(hash('sha256', 'hashMe'), jsHash('hashMe', 'sha256'));
}
}
118 changes: 118 additions & 0 deletions tests/SingJsConnectTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php
/**
* @author Alexandre (DaazKu) Chouinard <alexandre.c@vanillaforums.com>
* @copyright 2009-2017 Vanilla Forums Inc.
* @license GNU GPLv2 http://www.opensource.org/licenses/gpl-2.0.php
*/

namespace JsConnect\Tests;

/**
* Unit tests signJsConnect
*/
class SignJsConnectTest extends \PHPUnit_Framework_TestCase {

/**
* @param $data
* @param $clientID
* @param $secret
* @param $hashType
* @param $returnData
* @param $expectedResult
*
* @dataProvider provideSignJsConnectTests
*/
public function testSignJsConnect($data, $clientID, $secret, $hashType, $returnData, $expectedResult) {
$this->assertEquals(signJsConnect($data, $clientID, $secret, $hashType, $returnData), $expectedResult);
}


/**
* Provide signature to sign
*
* @return array Returns a test array.
*/
public function provideSignJsConnectTests() {
return [
'default' => [
[
'name' => 'John PHP',
'email' => 'john.php@example.com',
'unique_id' => '123',
],
'clientID',
'secret',
'sha256',
false,
'71528bfbb99aba97734f79beab6d1eca1416e05a0587e9ab55b99095753f74b6',
],
'unordered' => [
[
'unique_id' => '123',
'email' => 'john.php@example.com',
'name' => 'John PHP',
],
'clientID',
'secret',
'sha256',
false,
'71528bfbb99aba97734f79beab6d1eca1416e05a0587e9ab55b99095753f74b6',
],
'incorrectKeyCase' => [
[
'Name' => 'John PHP',
'eMail' => 'john.php@example.com',
'UNIQUE_id' => '123',
],
'clientID',
'secret',
'sha256',
false,
'71528bfbb99aba97734f79beab6d1eca1416e05a0587e9ab55b99095753f74b6',
],
'trueAsHashType' => [
[
'Name' => 'John PHP',
'eMail' => 'john.php@example.com',
'unique_id' => '123',
],
'clientID',
'secret',
true,
false,
'f1639a1838bd904cb967423be0567802',
],
'extraInfo' => [
[
'unique_id' => '123',
'email' => 'john.php@example.com',
'name' => 'John PHP',
'custom_field' => 'custom',
],
'clientID',
'secret',
'sha256',
false,
'72976aaaa96cb1acc94aa8c1638a0b3e10bb638e3985e25f60f6db79f65fcefb',
],
'defaultReturnData' => [
[
'name' => 'John PHP',
'email' => 'john.php@example.com',
'unique_id' => '123',
],
'clientID',
'secret',
'sha256',
true,
[
'name' => 'John PHP',
'email' => 'john.php@example.com',
'unique_id' => '123',
'client_id' => 'clientID',
'sig' => '71528bfbb99aba97734f79beab6d1eca1416e05a0587e9ab55b99095753f74b6',
]
],
];
}
}
Loading

0 comments on commit 8a036f0

Please sign in to comment.