Prepare settings for the API in the admin page and during the install
API settings: - api.enabled - api.secret The API settings will be initialized (and the secret generated) with an update method.
This commit is contained in:
parent
624f999fb7
commit
cbfdcff261
7 changed files with 142 additions and 2 deletions
|
@ -256,6 +256,29 @@ public function updateMethodDatastoreIds()
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize API settings:
|
||||
* - api.enabled: true
|
||||
* - api.secret: generated secret
|
||||
*/
|
||||
public function updateMethodApiSettings()
|
||||
{
|
||||
if ($this->conf->exists('api.secret')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->conf->set('api.enabled', true);
|
||||
$this->conf->set(
|
||||
'api.secret',
|
||||
generate_api_secret(
|
||||
$this->conf->get('credentials.login'),
|
||||
$this->conf->get('credentials.salt')
|
||||
)
|
||||
);
|
||||
$this->conf->write($this->isLoggedIn);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -231,3 +231,29 @@ function autoLocale($headerLocale)
|
|||
}
|
||||
setlocale(LC_ALL, $attempts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a default API secret.
|
||||
*
|
||||
* Note that the random-ish methods used in this function are predictable,
|
||||
* which makes them NOT suitable for crypto.
|
||||
* BUT the random string is salted with the salt and hashed with the username.
|
||||
* It makes the generated API secret secured enough for Shaarli.
|
||||
*
|
||||
* PHP 7 provides random_int(), designed for cryptography.
|
||||
* More info: http://stackoverflow.com/questions/4356289/php-random-string-generator
|
||||
|
||||
* @param string $username Shaarli login username
|
||||
* @param string $salt Shaarli password hash salt
|
||||
*
|
||||
* @return string|bool Generated API secret, 12 char length.
|
||||
* Or false if invalid parameters are provided (which will make the API unusable).
|
||||
*/
|
||||
function generate_api_secret($username, $salt)
|
||||
{
|
||||
if (empty($username) || empty($salt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return str_shuffle(substr(hash_hmac('sha512', uniqid($salt), $username), 10, 12));
|
||||
}
|
||||
|
|
12
index.php
12
index.php
|
@ -1142,6 +1142,8 @@ function renderPage($conf, $pluginManager)
|
|||
$conf->set('feed.rss_permalinks', !empty($_POST['enableRssPermalinks']));
|
||||
$conf->set('updates.check_updates', !empty($_POST['updateCheck']));
|
||||
$conf->set('privacy.hide_public_links', !empty($_POST['hidePublicLinks']));
|
||||
$conf->set('api.enabled', !empty($_POST['apiEnabled']));
|
||||
$conf->set('api.secret', escape($_POST['apiSecret']));
|
||||
try {
|
||||
$conf->write(isLoggedIn());
|
||||
}
|
||||
|
@ -1170,6 +1172,8 @@ function renderPage($conf, $pluginManager)
|
|||
$PAGE->assign('enable_rss_permalinks', $conf->get('feed.rss_permalinks', false));
|
||||
$PAGE->assign('enable_update_check', $conf->get('updates.check_updates', true));
|
||||
$PAGE->assign('hide_public_links', $conf->get('privacy.hide_public_links', false));
|
||||
$PAGE->assign('api_enabled', $conf->get('api.enabled', true));
|
||||
$PAGE->assign('api_secret', $conf->get('api.secret'));
|
||||
$PAGE->renderPage('configure');
|
||||
exit;
|
||||
}
|
||||
|
@ -1952,6 +1956,14 @@ function install($conf)
|
|||
$conf->set('general.title', 'Shared links on '.escape(index_url($_SERVER)));
|
||||
}
|
||||
$conf->set('updates.check_updates', !empty($_POST['updateCheck']));
|
||||
$conf->set('api.enabled', !empty($_POST['enableApi']));
|
||||
$conf->set(
|
||||
'api.secret',
|
||||
generate_api_secret(
|
||||
$this->conf->get('credentials.login'),
|
||||
$this->conf->get('credentials.salt')
|
||||
)
|
||||
);
|
||||
try {
|
||||
// Everything is ok, let's create config file.
|
||||
$conf->write(isLoggedIn());
|
||||
|
|
|
@ -271,7 +271,7 @@ public function testConfigToJsonNothingToDo()
|
|||
public function testEscapeConfig()
|
||||
{
|
||||
$sandbox = 'sandbox/config';
|
||||
copy(self::$configFile .'.json.php', $sandbox .'.json.php');
|
||||
copy(self::$configFile . '.json.php', $sandbox . '.json.php');
|
||||
$this->conf = new ConfigManager($sandbox);
|
||||
$title = '<script>alert("title");</script>';
|
||||
$headerLink = '<script>alert("header_link");</script>';
|
||||
|
@ -286,7 +286,43 @@ public function testEscapeConfig()
|
|||
$this->assertEquals(escape($title), $this->conf->get('general.title'));
|
||||
$this->assertEquals(escape($headerLink), $this->conf->get('general.header_link'));
|
||||
$this->assertEquals(escape($redirectorUrl), $this->conf->get('redirector.url'));
|
||||
unlink($sandbox .'.json.php');
|
||||
unlink($sandbox . '.json.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test updateMethodApiSettings(): create default settings for the API (enabled + secret).
|
||||
*/
|
||||
public function testUpdateApiSettings()
|
||||
{
|
||||
$confFile = 'sandbox/config';
|
||||
copy(self::$configFile .'.json.php', $confFile .'.json.php');
|
||||
$conf = new ConfigManager($confFile);
|
||||
$updater = new Updater(array(), array(), $conf, true);
|
||||
|
||||
$this->assertFalse($conf->exists('api.enabled'));
|
||||
$this->assertFalse($conf->exists('api.secret'));
|
||||
$updater->updateMethodApiSettings();
|
||||
$conf->reload();
|
||||
$this->assertTrue($conf->get('api.enabled'));
|
||||
$this->assertTrue($conf->exists('api.secret'));
|
||||
unlink($confFile .'.json.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test updateMethodApiSettings(): already set, do nothing.
|
||||
*/
|
||||
public function testUpdateApiSettingsNothingToDo()
|
||||
{
|
||||
$confFile = 'sandbox/config';
|
||||
copy(self::$configFile .'.json.php', $confFile .'.json.php');
|
||||
$conf = new ConfigManager($confFile);
|
||||
$conf->set('api.enabled', false);
|
||||
$conf->set('api.secret', '');
|
||||
$updater = new Updater(array(), array(), $conf, true);
|
||||
$updater->updateMethodApiSettings();
|
||||
$this->assertFalse($conf->get('api.enabled'));
|
||||
$this->assertEmpty($conf->get('api.secret'));
|
||||
unlink($confFile .'.json.php');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -253,4 +253,21 @@ public function testIsSessionIdInvalid()
|
|||
is_session_id_valid('c0ZqcWF3VFE2NmJBdm1HMVQ0ZHJ3UmZPbTFsNGhkNHI=')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test generateSecretApi.
|
||||
*/
|
||||
public function testGenerateSecretApi()
|
||||
{
|
||||
$this->assertEquals(12, strlen(generate_api_secret('foo', 'bar')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test generateSecretApi with invalid parameters.
|
||||
*/
|
||||
public function testGenerateSecretApiInvalid()
|
||||
{
|
||||
$this->assertFalse(generate_api_secret('', ''));
|
||||
$this->assertFalse(generate_api_secret(false, false));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,20 @@
|
|||
<label for="updateCheck"> Notify me when a new release is ready</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>Enable API</b></td>
|
||||
<td>
|
||||
<input type="checkbox" name="apiEnabled" id="apiEnabled"
|
||||
{if="$api_enabled"}checked{/if}/>
|
||||
<label for="apiEnabled"> Allow third party software to use Shaarli such as mobile application.</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>API secret</b></td>
|
||||
<td>
|
||||
<input type="text" name="apiSecret" id="apiSecret" size="50" value="{$api_secret}" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
|
|
@ -14,6 +14,18 @@ <h1>Shaarli</h1>
|
|||
<tr><td valign="top"><b>Update:</b></td><td>
|
||||
<input type="checkbox" name="updateCheck" id="updateCheck" checked="checked"><label for="updateCheck"> Notify me when a new release is ready</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<b>API:</b>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="enableApi" id="enableApi" checked="checked">
|
||||
<label for="enableApi">
|
||||
Enable Shaarli's API.
|
||||
Allow third party software to use Shaarli such as mobile application.
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td colspan="2"><input type="submit" name="Save" value="Save config" class="bigbutton"></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
|
|
Loading…
Reference in a new issue