Skip to content
Open
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
13 changes: 13 additions & 0 deletions DefaultSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,16 @@ class_alias( 'SEQL\ByHttpRequestQueryLookup', 'SMWExternalAskQueryLookup' );
* into MediaWiki's interwiki table or through this setting.
*/
$GLOBALS['seqlgExternalRepositoryEndpoints'] = array();

/**
* An array that defines credentials to access remote wikis in case they're read-protected
* Array keys should be named after interwiki prefixes from "seqlgExternalRepositoryEndpoints"
* and contain an array with "username" and "password" keys
*/
$GLOBALS['seqlgExternalRepositoryCredentials'] = array();

/**
* An array defines list of namespaces allowed to execute queries against remote sources.
* Keep empty to allow every namespace.
*/
$GLOBALS['seqlgExternalQueryEnabledNamespaces'] = array();
81 changes: 80 additions & 1 deletion src/ByHttpRequest/QueryResultFetcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,28 @@ class QueryResultFetcher {
*/
private $httpResponseCacheLifetime;

/**
* @var array
*/
private $credentials;

/**
* @var string
*/
private static $cookies;

/**
* @since 1.0
*
* @param HttpRequestFactory $httpRequestFactory
* @param QueryResultFactory $queryResultFactory
* @param JsonResponseParser $jsonResponseParser
*/
public function __construct( HttpRequestFactory $httpRequestFactory, QueryResultFactory $queryResultFactory, JsonResponseParser $jsonResponseParser ) {
public function __construct( HttpRequestFactory $httpRequestFactory, QueryResultFactory $queryResultFactory, JsonResponseParser $jsonResponseParser, $credentials ) {
$this->httpRequestFactory = $httpRequestFactory;
$this->queryResultFactory = $queryResultFactory;
$this->jsonResponseParser = $jsonResponseParser;
$this->credentials = $credentials;
}

/**
Expand Down Expand Up @@ -99,6 +110,65 @@ public function setHttpResponseCacheLifetime( $httpResponseCacheLifetime ) {
$this->httpResponseCacheLifetime = $httpResponseCacheLifetime;
}

/**
* Authenticates query against remote wiki using 'login' api and stores
* cookies to use on other requests
*
* @param array $credentials
*/
public function doAuthenticateRemoteWiki( $credentials ) {

$cookiefile = 'seql_'.time();

$httpRequest = $this->httpRequestFactory->newCurlRequest();

$httpRequest->setOption( CURLOPT_FOLLOWLOCATION, true );

$httpRequest->setOption( CURLOPT_RETURNTRANSFER, true );
$httpRequest->setOption( CURLOPT_FAILONERROR, true );
$httpRequest->setOption( CURLOPT_SSL_VERIFYPEER, false );
$httpRequest->setOption( CURLOPT_COOKIESESSION, true );
$httpRequest->setOption( CURLOPT_COOKIEJAR, $cookiefile );
$httpRequest->setOption( CURLOPT_COOKIEFILE, $cookiefile );

$httpRequest->setOption( CURLOPT_URL, $this->httpRequestEndpoint . '?action=query&format=json&meta=tokens&type=login' );

$response = $httpRequest->execute();
$result = json_decode( $response, true );

if( isset( $result['query']['tokens']['logintoken'] ) ) {

$token = $result['query']['tokens']['logintoken'];

$httpRequest->setOption( CURLOPT_FOLLOWLOCATION, true );
$httpRequest->setOption( CURLOPT_RETURNTRANSFER, true );
$httpRequest->setOption( CURLOPT_FAILONERROR, true );
$httpRequest->setOption( CURLOPT_SSL_VERIFYPEER, false );
$httpRequest->setOption( CURLOPT_POST, true );
$httpRequest->setOption( CURLOPT_URL, $this->httpRequestEndpoint );
$httpRequest->setOption( CURLOPT_COOKIEJAR, $cookiefile );
$httpRequest->setOption( CURLOPT_COOKIEFILE, $cookiefile );

$httpRequest->setOption( CURLOPT_POSTFIELDS, http_build_query( array(
'action' => 'login',
'format' => 'json',
'lgname' => $credentials['username'],
'lgpassword' => $credentials['password'],
'lgtoken' => $token
))
);

$response = $httpRequest->execute();
$result = json_decode( $response, true );

if ( isset( $result['login']['lguserid'] ) ) {
self::$cookies = $cookiefile;
}

}

}

/**
* @since 1.0
*
Expand All @@ -110,6 +180,10 @@ public function fetchQueryResult( Query $query ) {

$this->doResetPrintRequestsToQuerySource( $query );

if( $this->credentials && !self::$cookies ) {
$this->doAuthenticateRemoteWiki( $this->credentials );
}

list( $result, $isFromCache ) = $this->doMakeHttpRequestFor( $query );

if ( $result === array() || $result === false || $result === null ) {
Expand Down Expand Up @@ -185,6 +259,11 @@ private function doMakeHttpRequestFor( $query ) {
'Content-Type: application/json; charset=utf-8'
) );

if( self::$cookies ) {
$httpRequest->setOption( CURLOPT_COOKIEJAR, self::$cookies );
$httpRequest->setOption( CURLOPT_COOKIEFILE, self::$cookies );
}

$response = $httpRequest->execute();

return array( json_decode( $response, true ), $httpRequest->isFromCache() );
Expand Down
12 changes: 9 additions & 3 deletions src/ByHttpRequestQueryLookup.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,25 @@ public function getQueryResult( Query $query ) {
return $this->queryResultFactory->newEmptyQueryResult( $query );
}

return $this->fetchQueryResultFor( $query, $interwiki );
$credentials = false;
if ( isset( $GLOBALS['seqlgExternalRepositoryCredentials'][ $interwiki->getWikiID() ] ) ) {
$credentials = $GLOBALS['seqlgExternalRepositoryCredentials'][ $interwiki->getWikiID() ];
}

return $this->fetchQueryResultFor( $query, $interwiki, $credentials );
}

protected function tryToMatchInterwikiFor( Query $query ) {
return Interwiki::fetch( $query->getQuerySource() );
}

protected function fetchQueryResultFor( Query $query, $interwiki ) {
protected function fetchQueryResultFor( Query $query, $interwiki, $credentials = false ) {

$queryResultFetcher = new QueryResultFetcher(
new HttpRequestFactory( $this->getCacheFactory()->newMediaWikiCompositeCache( $GLOBALS['seqlgHttpResponseCacheType'] ) ),
$this->queryResultFactory,
new JsonResponseParser( new DataValueDeserializer( $query->getQuerySource() ) )
new JsonResponseParser( new DataValueDeserializer( $query->getQuerySource() ) ),
$credentials
);

$queryResultFetcher->setHttpRequestEndpoint( $interwiki->getApi() );
Expand Down
30 changes: 30 additions & 0 deletions src/HookRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,36 @@ private function addCallbackHandlers( $options ) {
$this->handlers['InterwikiLoadPrefix'] = function( $prefix, &$interwiki ) use( $dynamicInterwikiPrefixLoader ) {
return $dynamicInterwikiPrefixLoader->tryToLoadIwMapForExternalRepository( $prefix, $interwiki );
};

/**
* Prevents ask parser function with "source" parameter defined from
* being executed outside of allowed namespaces. This supports transclusion too.
*
* @param \Parser $parser
* @param \PPFrame $frame
* @param $args
* @param $override
*/
$this->handlers['smwAskParserFunction'] = $this->handlers['smwShowParserFunction'] = function( $parser, $frame, $args, &$override ) {
if( $frame ) {
$params = [];
foreach ($args as $key => $value) {
if ( $key == 0 || ( $value !== '' && $value{0} === '?' ) ) {
continue;
}
if ( strpos( $value, '=' ) === false ) {
continue;
}
$pair = explode('=', $value);
$params[$pair[0]] = $pair[1];
}

if( array_key_exists('source', $params) && !in_array( $frame->getTitle()->getNamespace(), $GLOBALS['seqlgExternalQueryEnabledNamespaces'] ) ) {
$override = 'Warning: source parameter is not allowed in the namespace!';
}
}
};

}

}
2 changes: 1 addition & 1 deletion src/QueryEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ private static function doSerializePrintouts( $query ) {

foreach ( $query->getExtraPrintouts() as $printout ) {
$serialization = $printout->getSerialisation();
if ( $serialization !== '?#' ) {
if ( $serialization !== '?#' && $serialization !== '' ) {
// #show adds an extra = at the end which is interpret as
// requesting an empty result hence it is removed
$printouts[] = substr( $serialization, -1 ) === '=' ? substr( $serialization, 0, -1 ) : $serialization;
Expand Down