aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md73
-rwxr-xr-xgsxcl9
-rw-r--r--gsxlib.php128
-rw-r--r--runtests.php22
4 files changed, 160 insertions, 72 deletions
diff --git a/README.md b/README.md
index 64e02ba..49e2a14 100644
--- a/README.md
+++ b/README.md
@@ -10,27 +10,30 @@ validation (as opposed to burdening Apple's servers with totally invalid request
Requrements
===========
-- SOAP support in your PHP installation
-- A GSX account with the "Can access Web Services" privilege enabled
+- SOAP support in your PHP
+- Client certificates for GSX access
+- Whitelisted IP address of the source of your requests
+- GSX account with the "Can access Web Services" privilege enabled
+
Usage
=====
Best illustrated with a simple example:
-```php
-<?php
-
- include 'gsxlib/gsxlib.php';
- $gsx = GsxLib::getInstance($sold_to, $username, $password);
- $info = $gsx->warrantyStatus($serialnumber);
- echo $info->productDescription;
- > MacBook Pro (15-inch 2.4/2.2GHz)
+ <?php
-?>
-```
+ include 'gsxlib/gsxlib.php';
+ $_ENV['GSX_CERT'] = '/path/to/gsx/client/cert.pem';
+ $_ENV['GSX_KEYPASS'] = 'MySuperSecretPrivateKeyPassPhrase';
+ $gsx = GsxLib::getInstance($sold_to, $username);
+ $info = $gsx->warrantyStatus($serialnumber);
+ echo $info->productDescription;
+ > MacBook Pro (15-inch 2.4/2.2GHz)
+
+ ?>
-US users should remember to set the fifth argument of the constructor to 'am'.
+If you're in the US, remember to set the fifth argument to the constructor to 'am'.
gsxcl
@@ -39,8 +42,48 @@ gsxcl
The package includes a rudimentary command line client to the GSX API called _gsxcl_. It can perform various functions in the library and is meant
mainly as a simple test tool for the library.
-##License##
-
+
+FAQ
+===
+
+### Q: How do I create the necessary PEM file?
+A: The PEM file must be a concatenation of the certificate you got from Apple and your private key file. You can create this from the Terminal:
+
+ $ cat Applecare-APP1234-0000123456.Test.apple.com.chain.pem privatekey.pem > certbundle.pem
+
+After that you would use _certbundle.pem_ as your client certificate. The contents of _certbundle.pem_ should look something like this:
+
+ -----BEGIN CERTIFICATE-----
+ BLASOQ()*Q#()**)REW)*(EW*)*E)WUR)*EW(UR)
+ ...
+ -----END CERTIFICATE-----
+ -----BEGIN CERTIFICATE-----
+ 0990320003q43090435J403439590S-S=DS=-
+ ...
+ -----END CERTIFICATE-----
+ -----BEGIN CERTIFICATE-----
+ )_#_)#)$IK_#@))KDE_)FD_SF)DSF_DS)FDS_FDSFSD
+ ....
+ -----END CERTIFICATE-----
+ -----BEGIN RSA PRIVATE KEY-----
+ Proc-Type: ....
+ DEK-Info: ...
+ BUNCH OF GIBBERISH
+ -----END RSA PRIVATE KEY-----
+
+
+### Q: Do I need to make changes to my web server configuration for the SSL authentication to work?
+A: No, the library takes care of everything. That's why the certificate path and passphrase are implemented as environment variables. This
+ensures the certificate is sent with each request and you only have to define the paths once in your code.
+
+### Q: How can I remove the passphrase from my private key?
+
+ $ openssl rsa -in privatekey.pem -out privatekey.nopass.pem
+
+
+License
+=======
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
diff --git a/gsxcl b/gsxcl
index 0d5e9aa..81705cf 100755
--- a/gsxcl
+++ b/gsxcl
@@ -25,11 +25,10 @@ require 'gsxlib.php';
if( count( $argv ) < 6 ) {
echo <<<EOT
-usage: gsxcl [--debug] -s sold-to -u username -p password [-r region] [-e environment] [-f format] verb noun
+usage: gsxcl [--debug] -s sold-to -u username [-r region] [-e environment] [-f format] verb noun
--debug Report all errors
-s sold-to your GSX Sold-To account
-u username the Apple ID with GSX WS API access
- -p password the password for the Apple ID
-r region either "am" (America), "emea" (default, Europe, Middle-East, Africa)
"apac" (Asia-Pacific) or "la" (Latin America)
-e environment the GSX environment. Either empty (production, default), "it" or "ut"
@@ -74,7 +73,11 @@ switch( $noun )
}
}
-$gsx = GsxLib::getInstance( $opts['s'], $opts['u'], $opts['p'], $environment, $region );
+if (!$_ENV['GSX_CERT']) {
+ exit("The GSX_CERT environment variable must be set to the path to your GSX client certificate");
+}
+
+$gsx = GsxLib::getInstance( $opts['s'], $opts['u'], $environment, $region );
if( isset( $opts['d'] )) {
$data = $opts['d'];
diff --git a/gsxlib.php b/gsxlib.php
index e5b1297..a520653 100644
--- a/gsxlib.php
+++ b/gsxlib.php
@@ -13,37 +13,31 @@
*/
class GsxLib
{
- private $client;
- private $region;
- private $session_id;
- private $environment;
+ private $client; // SoapClient instance
+ private $region; // GSX region code
+ private $session_id; // Current GSX SessionID
+ private $environment; // Current GSX environment
- //IT: https://gsxws%s.apple.com/wsdl/%sAsp/gsx-%sAsp.wsdl
- //PROD: https://gsxws2.apple.com/wsdl/%sAsp/gsx-%sAsp.wsdl
- private $wsdl = 'https://gsxws%s.apple.com/wsdl/%sAsp/gsx-%sAsp.wsdl';
+ private $wsdl = 'https://gsxapi%s.apple.com/wsdl/%sAsp/gsx-%sAsp.wsdl';
- static $_instance;
+ static $_instance; // Reference to GsxLib instance
const timeout = 30; // session timeout in minutes
public static function getInstance(
- $account,
+ $sold_to,
$username,
- $password,
$environment = '',
$region = 'emea',
- $tz = 'CEST',
- $lang = 'en')
+ $tz = 'CEST')
{
if(!(self::$_instance instanceof self)) {
self::$_instance = new self(
- $account,
+ $sold_to,
$username,
- $password,
$environment,
$region,
- $tz,
- $lang
+ $tz
);
}
@@ -54,20 +48,18 @@ class GsxLib
private function __clone() {}
private function __construct(
- $account,
+ $sold_to,
$username,
- $password,
$environment = '',
$region = 'emea',
- $tz = 'CEST',
- $lang = 'en' )
+ $tz = 'CEST' )
{
if(!class_exists('SoapClient')) {
throw new GsxException('Looks like your PHP lacks SOAP support');
}
- if(!preg_match('/\d+/', $account)) {
- throw new GsxException('Invalid Sold-To: ' . $account);
+ if(!preg_match('/\d+/', $sold_to)) {
+ throw new GsxException('Invalid Sold-To: ' . $sold_to);
}
$regions = array('am', 'emea', 'apac', 'la');
@@ -89,31 +81,41 @@ class GsxLib
$error = sprintf($error, $environment, implode(', ', $envirs));
throw new GsxException($error);
}
- } else {
- // GSX2...
- $environment = '2';
}
+ $this->cert_path = $_ENV['GSX_CERT'];
+ $this->cert_pass = $_ENV['GSX_KEYPASS'];
+
+ if (!is_readable($this->cert_path)) {
+ throw new GsxException("Cannot read SSL certificate");
+ }
+
$this->wsdl = sprintf($this->wsdl, $environment, $region, $region);
+ $client_options = array(
+ 'trace' => TRUE,
+ 'exceptions' => TRUE,
+ 'local_cert' => $this->cert_path,
+ 'passphrase' => $this->cert_pass,
+ );
+
$this->client = new SoapClient(
- $this->wsdl, array('exceptions' => TRUE, 'trace' => 1)
+ $this->wsdl, $client_options
);
if(!$this->client) {
throw new GsxException('Failed to create SOAP client.');
}
- if(@$_SESSION['_gsxlib_timeout'][$account] > time()) {
- // return $this->session_id = $_SESSION['_gsxlib_id'][$account];
+ if(@$_SESSION['_gsxlib_timeout'][$sold_to] > time()) {
+ // return $this->session_id = $_SESSION['_gsxlib_id'][$sold_to];
}
$a = array(
'AuthenticateRequest' => array(
'userId' => $username,
- 'password' => $password,
- 'serviceAccountNo' => $account,
- 'languageCode' => $lang,
+ 'serviceAccountNo' => $sold_to,
+ 'languageCode' => 'en',
'userTimeZone' => $tz,
)
);
@@ -124,19 +126,24 @@ class GsxLib
->AuthenticateResponse
->userSessionId;
} catch(SoapFault $e) {
- if($environment == '2') $environment = 'production';
+ syslog(LOG_ERR, $e);
+ syslog(LOG_ERR, $this->wsdl);
+ syslog(LOG_ERR, $this->client->__getLastRequest());
+ syslog(LOG_ERR, $this->client->__getLastResponse());
+ syslog(LOG_ERR, $this->client->__getLastResponseHeaders());
+
+ if($environment == '') $environment = 'production';
- $error = 'Authentication with GSX failed. Does this account have access to '
- .$environment." environment?\n";
+ $error = 'Authentication with GSX failed. Does this account have access to '.$environment."?\n";
throw new GsxException($error);
}
// there's a session going, put the credentials in there
if(session_id()) {
- $_SESSION['_gsxlib_id'][$account] = $this->session_id;
+ $_SESSION['_gsxlib_id'][$sold_to] = $this->session_id;
$timeout = time()+(60*self::timeout);
- $_SESSION['_gsxlib_timeout'][$account] = $timeout;
+ $_SESSION['_gsxlib_timeout'][$sold_to] = $timeout;
}
}
@@ -181,6 +188,24 @@ class GsxLib
}
+ /**
+ * The Reported Symptom/Issue API allows partners to fetch the information related to symptoms and issues.
+ * If all the validations go through, api returns a list of valid symptoms/issues according to the input data.
+ * Otherwise api returns appropriate error message.
+ * @param mixed $query
+ */
+ public function fetchSymptomIssue($query)
+ {
+ if(!is_array($query)) {
+ $like = self::looksLike($query);
+ $query = array($like => $query);
+ }
+
+ $rd = array('ReportedSymptomIssue' => array('requestData' => $query));
+ return $this->request($rd)->reportedSymptomIssueResponse;
+
+ }
+
public function fetchiOsActivation($query)
{
if(!is_array($query)) {
@@ -277,23 +302,28 @@ class GsxLib
'unreceivedModules' => 'N',
);
- // provide "shortcuts" for dispatch ID and SN
- switch(self::looksLike($query)) {
- case 'dispatchId':
- $query = array('repairConfirmationNumber' => $query);
- break;
- case 'serialNumber':
- $query = array('serialNumber' => $query);
- break;
- }
+ if(!is_array($query)) {
+ // provide "shortcuts" for dispatch ID and SN
+ switch(self::looksLike($query)) {
+ case 'dispatchId':
+ $query = array('repairConfirmationNumber' => $query);
+ break;
+ case 'serialNumber':
+ $query = array('serialNumber' => $query);
+ break;
+ }
- $query = array_merge($fields, $query);
+ $query = array_merge($fields, $query);
+
+ }
+
$req = array( 'RepairLookupRequest' => array(
'userSession' => array('userSessionId' => $this->session_id),
'lookupRequestData' => $query
));
- $response = $this->client->RepairLookup($req)->RepairLookupResponse;
+ $response = $this->client->RepairLookup($req)
+ ->RepairLookupResponse;
return $response->lookupResponseData;
}
@@ -438,7 +468,9 @@ class GsxLib
}
- $req = array('PartsLookup' => array('lookupRequestData' => $query));
+ $req = array('PartsLookup' => array(
+ 'lookupRequestData' => $query
+ ));
$result = $this->request($req)->parts;
// always return an array
diff --git a/runtests.php b/runtests.php
index 6619cc5..fa87c70 100644
--- a/runtests.php
+++ b/runtests.php
@@ -6,23 +6,31 @@ require_once('gsxlib.php');
class GsxlibTest extends UnitTestCase
{
function setUp() {
- global $argv;
- $this->gsx = GsxLib::getInstance($argv[1], $argv[2], $argv[3], 'ut', 'emea', 'CEST', 'es');
+ $this->sn = $_ENV['GSX_SN'];
+ $this->gsx = GsxLib::getInstance($_ENV['GSX_SOLDTO'], $_ENV['GSX_USER'], 'ut');
}
function testWarranty() {
- $wty = $this->gsx->warrantyStatus('RM6501PXU9C');
+ $wty = $this->gsx->warrantyStatus($this->sn);
$this->assertEqual($wty->warrantyStatus, 'Out Of Warranty (No Coverage)');
}
+ function testSymptomIssue() {
+ $r = $this->gsx->fetchSymptomIssue($this->sn);
+ $this->assertEqual($r->symptoms[0]->reportedSymptomCode, 6115);
+ $this->assertEqual($r->symptoms[1]->reportedSymptomDesc, "Accidental damage");
+ }
+
function testCreateCarryInRepair() {
+ $symptom = $this->gsx->fetchSymptomIssue($this->sn)->symptoms[0];
+
$repairData = array(
'shipTo' => '6191',
- 'serialNumber' => 'RM6501PXU9C',
+ 'serialNumber' => $this->sn,
'diagnosedByTechId' => 'USA022SN',
'symptom' => 'Sample symptom',
'diagnosis' => 'Sample diagnosis',
- 'unitReceivedDate' => '07/02/13',
+ 'unitReceivedDate' => '07/25/15',
'unitReceivedTime' => '12:40 PM',
'notes' => 'A sample notes',
'poNumber' => '11223344',
@@ -47,13 +55,15 @@ class GsxlibTest extends UnitTestCase
'lastName' => 'Customer lastname',
'primaryPhone' => '4088887766'
),
+ 'reportedSymptomCode' => $symptom->reportedSymptomCode,
+ 'reportedIssueCode' => 'IP025',
);
$this->gsx->createCarryinRepair($repairData);
}
- function testCreateMailInRepair() {
+ function _testCreateMailInRepair() {
$repairData = array(
'shipTo' => '6191',
'accidentalDamage' => false,