From b18073d5a89ce6058a0985960f01391cf93c915a Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 13 May 2021 14:58:55 +0000 Subject: [PATCH] Repurposed OAuth frontend handling, store the scope --- database.sql | 32 ++++++++- mod/settings.php | 69 +++----------------- src/Module/Api/Mastodon/Apps.php | 6 +- src/Module/BaseApi.php | 6 +- src/Module/OAuth/Authorize.php | 2 +- static/dbstructure.config.php | 11 +++- static/dbview.config.php | 19 ++++++ view/templates/settings/oauth.tpl | 57 +++++++--------- view/theme/frio/templates/settings/oauth.tpl | 58 ++++++---------- 9 files changed, 121 insertions(+), 139 deletions(-) diff --git a/database.sql b/database.sql index bbcd479bc9..99386abf45 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2021.06-dev (Siberian Iris) --- DB_UPDATE_VERSION 1416 +-- DB_UPDATE_VERSION 1417 -- ------------------------------------------ @@ -375,6 +375,9 @@ CREATE TABLE IF NOT EXISTS `application` ( `redirect_uri` varchar(255) NOT NULL COMMENT '', `website` varchar(255) COMMENT '', `scopes` varchar(255) COMMENT '', + `read` boolean COMMENT 'Read scope', + `write` boolean COMMENT 'Write scope', + `follow` boolean COMMENT 'Follow scope', PRIMARY KEY(`id`), UNIQUE INDEX `client_id` (`client_id`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='OAuth application'; @@ -387,7 +390,11 @@ CREATE TABLE IF NOT EXISTS `application-token` ( `uid` mediumint unsigned NOT NULL COMMENT 'Owner User id', `code` varchar(64) NOT NULL COMMENT '', `access_token` varchar(64) NOT NULL COMMENT '', - `created_at` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'creation time', + `created_at` datetime NOT NULL COMMENT 'creation time', + `scopes` varchar(255) COMMENT '', + `read` boolean COMMENT 'Read scope', + `write` boolean COMMENT 'Write scope', + `follow` boolean COMMENT 'Follow scope', PRIMARY KEY(`application-id`,`uid`), INDEX `uid_id` (`uid`,`application-id`), FOREIGN KEY (`application-id`) REFERENCES `application` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, @@ -1500,6 +1507,27 @@ CREATE TABLE IF NOT EXISTS `workerqueue` ( INDEX `done_pid_priority_created` (`done`,`pid`,`priority`,`created`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Background tasks queue entries'; +-- +-- VIEW application-view +-- +DROP VIEW IF EXISTS `application-view`; +CREATE VIEW `application-view` AS SELECT + `application`.`id` AS `id`, + `application-token`.`uid` AS `uid`, + `application`.`name` AS `name`, + `application`.`redirect_uri` AS `redirect_uri`, + `application`.`website` AS `website`, + `application`.`client_id` AS `client_id`, + `application`.`client_secret` AS `client_secret`, + `application-token`.`code` AS `code`, + `application-token`.`access_token` AS `access_token`, + `application-token`.`created_at` AS `created_at`, + `application-token`.`scopes` AS `scopes`, + `application-token`.`read` AS `read`, + `application-token`.`write` AS `write`, + `application-token`.`follow` AS `follow` + FROM `application-token` INNER JOIN `application` ON `application-token`.`application-id` = `application`.`id`; + -- -- VIEW post-user-view -- diff --git a/mod/settings.php b/mod/settings.php index c8dbcb9105..3a3f0b65dc 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -500,77 +500,26 @@ function settings_content(App $a) } if (($a->argc > 1) && ($a->argv[1] === 'oauth')) { - if (($a->argc > 2) && ($a->argv[2] === 'add')) { - $tpl = Renderer::getMarkupTemplate('settings/oauth_edit.tpl'); - $o .= Renderer::replaceMacros($tpl, [ - '$form_security_token' => BaseModule::getFormSecurityToken("settings_oauth"), - '$title' => DI::l10n()->t('Add application'), - '$submit' => DI::l10n()->t('Save Settings'), - '$cancel' => DI::l10n()->t('Cancel'), - '$name' => ['name', DI::l10n()->t('Name'), '', ''], - '$key' => ['key', DI::l10n()->t('Consumer Key'), '', ''], - '$secret' => ['secret', DI::l10n()->t('Consumer Secret'), '', ''], - '$redirect' => ['redirect', DI::l10n()->t('Redirect'), '', ''], - '$icon' => ['icon', DI::l10n()->t('Icon url'), '', ''], - ]); - return $o; - } - - if (($a->argc > 3) && ($a->argv[2] === 'edit')) { - $r = q("SELECT * FROM clients WHERE client_id='%s' AND uid=%d", - DBA::escape($a->argv[3]), - local_user()); - - if (!DBA::isResult($r)) { - notice(DI::l10n()->t("You can't edit this application.")); - return; - } - $app = $r[0]; - - $tpl = Renderer::getMarkupTemplate('settings/oauth_edit.tpl'); - $o .= Renderer::replaceMacros($tpl, [ - '$form_security_token' => BaseModule::getFormSecurityToken("settings_oauth"), - '$title' => DI::l10n()->t('Add application'), - '$submit' => DI::l10n()->t('Update'), - '$cancel' => DI::l10n()->t('Cancel'), - '$name' => ['name', DI::l10n()->t('Name'), $app['name'] , ''], - '$key' => ['key', DI::l10n()->t('Consumer Key'), $app['client_id'], ''], - '$secret' => ['secret', DI::l10n()->t('Consumer Secret'), $app['pw'], ''], - '$redirect' => ['redirect', DI::l10n()->t('Redirect'), $app['redirect_uri'], ''], - '$icon' => ['icon', DI::l10n()->t('Icon url'), $app['icon'], ''], - ]); - return $o; - } - if (($a->argc > 3) && ($a->argv[2] === 'delete')) { BaseModule::checkFormSecurityTokenRedirectOnError('/settings/oauth', 'settings_oauth', 't'); - DBA::delete('clients', ['client_id' => $a->argv[3], 'uid' => local_user()]); + DBA::delete('application-token', ['application-id' => $a->argv[3], 'uid' => local_user()]); DI::baseUrl()->redirect('settings/oauth/', true); return; } - /// @TODO validate result with DBA::isResult() - $r = q("SELECT clients.*, tokens.id as oauth_token, (clients.uid=%d) AS my - FROM clients - LEFT JOIN tokens ON clients.client_id=tokens.client_id - WHERE clients.uid IN (%d, 0)", - local_user(), - local_user()); - + $applications = DBA::selectToArray('application-view', ['id', 'uid', 'name', 'website', 'scopes', 'created_at'], ['uid' => local_user()]); $tpl = Renderer::getMarkupTemplate('settings/oauth.tpl'); $o .= Renderer::replaceMacros($tpl, [ '$form_security_token' => BaseModule::getFormSecurityToken("settings_oauth"), - '$baseurl' => DI::baseUrl()->get(true), - '$title' => DI::l10n()->t('Connected Apps'), - '$add' => DI::l10n()->t('Add application'), - '$edit' => DI::l10n()->t('Edit'), - '$delete' => DI::l10n()->t('Delete'), - '$consumerkey' => DI::l10n()->t('Client key starts with'), - '$noname' => DI::l10n()->t('No name'), - '$remove' => DI::l10n()->t('Remove authorization'), - '$apps' => $r, + '$baseurl' => DI::baseUrl()->get(true), + '$title' => DI::l10n()->t('Connected Apps'), + '$name' => DI::l10n()->t('Name'), + '$website' => DI::l10n()->t('Home Page'), + '$created_at' => DI::l10n()->t('Created'), + '$delete' => DI::l10n()->t('Remove authorization'), + '$apps' => $applications, ]); return $o; } diff --git a/src/Module/Api/Mastodon/Apps.php b/src/Module/Api/Mastodon/Apps.php index 0fc206d43b..8205691dca 100644 --- a/src/Module/Api/Mastodon/Apps.php +++ b/src/Module/Api/Mastodon/Apps.php @@ -51,7 +51,7 @@ class Apps extends BaseApi $name = $_REQUEST['client_name'] ?? ''; $redirect = $_REQUEST['redirect_uris'] ?? ''; - $scopes = $_REQUEST['scopes'] ?? ''; + $scopes = $_REQUEST['scopes'] ?? 'read'; $website = $_REQUEST['website'] ?? ''; if (empty($name) || empty($redirect)) { @@ -67,6 +67,10 @@ class Apps extends BaseApi $fields['scopes'] = $scopes; } + $fields['read'] = (stripos($scopes, 'read') !== false); + $fields['write'] = (stripos($scopes, 'write') !== false); + $fields['follow'] = (stripos($scopes, 'follow') !== false); + if (!empty($website)) { $fields['website'] = $website; } diff --git a/src/Module/BaseApi.php b/src/Module/BaseApi.php index 6c2f13c590..a53c008c62 100644 --- a/src/Module/BaseApi.php +++ b/src/Module/BaseApi.php @@ -267,9 +267,9 @@ class BaseApi extends BaseModule $code = bin2hex(random_bytes(32)); $access_token = bin2hex(random_bytes(32)); - // @todo store the scope - - $fields = ['application-id' => $application['id'], 'uid' => $uid, 'code' => $code, 'access_token' => $access_token, 'created_at' => DateTimeFormat::utcNow(DateTimeFormat::MYSQL)]; + $fields = ['application-id' => $application['id'], 'uid' => $uid, 'code' => $code, 'access_token' => $access_token, 'scopes' => $scope, + 'read' => (stripos($scope, 'read') !== false), 'write' => (stripos($scope, 'write') !== false), + 'follow' => (stripos($scope, 'follow') !== false), 'created_at' => DateTimeFormat::utcNow(DateTimeFormat::MYSQL)]; if (!DBA::insert('application-token', $fields, Database::INSERT_UPDATE)) { return []; } diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index c956207705..57efe70c63 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -41,7 +41,7 @@ class Authorize extends BaseApi $client_id = $_REQUEST['client_id'] ?? ''; $client_secret = $_REQUEST['client_secret'] ?? ''; // Isn't normally provided. We will use it if present. $redirect_uri = $_REQUEST['redirect_uri'] ?? ''; - $scope = $_REQUEST['scope'] ?? ''; + $scope = $_REQUEST['scope'] ?? 'read'; $state = $_REQUEST['state'] ?? ''; if ($response_type != 'code') { diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 41515681e4..a074ef0b82 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1416); + define('DB_UPDATE_VERSION', 1417); } return [ @@ -436,6 +436,9 @@ return [ "redirect_uri" => ["type" => "varchar(255)", "not null" => "1", "comment" => ""], "website" => ["type" => "varchar(255)", "comment" => ""], "scopes" => ["type" => "varchar(255)", "comment" => ""], + "read" => ["type" => "boolean", "comment" => "Read scope"], + "write" => ["type" => "boolean", "comment" => "Write scope"], + "follow" => ["type" => "boolean", "comment" => "Follow scope"], ], "indexes" => [ "PRIMARY" => ["id"], @@ -449,7 +452,11 @@ return [ "uid" => ["type" => "mediumint unsigned", "not null" => "1", "primary" => "1", "foreign" => ["user" => "uid"], "comment" => "Owner User id"], "code" => ["type" => "varchar(64)", "not null" => "1", "comment" => ""], "access_token" => ["type" => "varchar(64)", "not null" => "1", "comment" => ""], - "created_at" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "creation time"], + "created_at" => ["type" => "datetime", "not null" => "1", "comment" => "creation time"], + "scopes" => ["type" => "varchar(255)", "comment" => ""], + "read" => ["type" => "boolean", "comment" => "Read scope"], + "write" => ["type" => "boolean", "comment" => "Write scope"], + "follow" => ["type" => "boolean", "comment" => "Follow scope"], ], "indexes" => [ "PRIMARY" => ["application-id", "uid"], diff --git a/static/dbview.config.php b/static/dbview.config.php index 94b81411b4..f8ebc05720 100644 --- a/static/dbview.config.php +++ b/static/dbview.config.php @@ -37,6 +37,25 @@ */ return [ + "application-view" => [ + "fields" => [ + "id" => ["application", "id"], + "uid" => ["application-token", "uid"], + "name" => ["application", "name"], + "redirect_uri" => ["application", "redirect_uri"], + "website" => ["application", "website"], + "client_id" => ["application", "client_id"], + "client_secret" => ["application", "client_secret"], + "code" => ["application-token", "code"], + "access_token" => ["application-token", "access_token"], + "created_at" => ["application-token", "created_at"], + "scopes" => ["application-token", "scopes"], + "read" => ["application-token", "read"], + "write" => ["application-token", "write"], + "follow" => ["application-token", "follow"], + ], + "query" => "FROM `application-token` INNER JOIN `application` ON `application-token`.`application-id` = `application`.`id`" + ], "post-user-view" => [ "fields" => [ "id" => ["post-user", "id"], diff --git a/view/templates/settings/oauth.tpl b/view/templates/settings/oauth.tpl index edb0ff63ec..955b5754dc 100644 --- a/view/templates/settings/oauth.tpl +++ b/view/templates/settings/oauth.tpl @@ -1,32 +1,25 @@ - -

{{$title}}

- - -
- - - - - {{foreach $apps as $app}} -
- - {{if $app.name}}

{{$app.name}}

{{else}}

{{$noname}}

{{/if}} - {{if $app.my}} - {{if $app.oauth_token}} -
- {{/if}} - {{/if}} - {{if $app.my}} -   -   - {{/if}} -
- {{/foreach}} - -
+
+

{{$title}}

+
+ + + + + + + + + + + {{foreach $apps as $app}} + + + + + + + {{/foreach}} + +
{{$name}}{{$website}}{{$created_at}}
{{$app.name}}{{$app.website}}{{$app.created_at}} 
+
+
diff --git a/view/theme/frio/templates/settings/oauth.tpl b/view/theme/frio/templates/settings/oauth.tpl index c6103cbc82..98cb96a3f8 100644 --- a/view/theme/frio/templates/settings/oauth.tpl +++ b/view/theme/frio/templates/settings/oauth.tpl @@ -1,44 +1,26 @@
{{* include the title template for the settings title *}} - {{include file="section_title.tpl" title=$title }} - - + {{include file="section_title.tpl" title=$title}}
- - - - {{foreach $apps as $app}} -
- - {{if $app.name}}

{{$app.name}}

{{else}}

{{$noname}}

{{/if}} - {{if $app.my}} - {{if $app.oauth_token}} -
- {{/if}} - {{/if}} - {{if $app.my}} -   - - {{/if}} -
- {{/foreach}} - + + + + + + + + + + {{foreach $apps as $app}} + + + + + + + {{/foreach}} + +
{{$name}}{{$website}}{{$created_at}}
{{$app.name}}{{$app.website}}{{$app.created_at}}