aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Zotlabs/Module/Tokens.php194
-rw-r--r--boot.php2
-rw-r--r--include/channel.php24
-rw-r--r--include/connections.php13
-rw-r--r--include/import.php58
-rw-r--r--include/security.php28
-rw-r--r--include/text.php2
-rw-r--r--install/schema_mysql.sql2
-rw-r--r--install/schema_postgres.sql2
-rw-r--r--view/tpl/tokens.tpl7
10 files changed, 282 insertions, 50 deletions
diff --git a/Zotlabs/Module/Tokens.php b/Zotlabs/Module/Tokens.php
index 31b219019..632e816ce 100644
--- a/Zotlabs/Module/Tokens.php
+++ b/Zotlabs/Module/Tokens.php
@@ -5,6 +5,11 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
+use Zotlabs\Lib\AccessList;
+use Zotlabs\Lib\Permcat;
+use Zotlabs\Lib\Libsync;
+
+require_once('include/security.php');
class Tokens extends Controller {
@@ -13,15 +18,20 @@ class Tokens extends Controller {
if(! local_channel())
return;
- if(! Apps::system_app_installed(local_channel(), 'Guest Access'))
- return;
-
$channel = App::get_channel();
+ if(! Apps::system_app_installed($channel['channel_id'], 'Guest Access'))
+ return;
+
check_form_security_token_redirectOnErr('tokens', 'tokens');
$token_errs = 0;
if(array_key_exists('token',$_POST)) {
$atoken_id = (($_POST['atoken_id']) ? intval($_POST['atoken_id']) : 0);
+
+ if (! $atoken_id) {
+ $atoken_guid = new_uuid();
+ }
+
$name = trim(escape_tags($_POST['name']));
$token = trim($_POST['token']);
if((! $name) || (! $token))
@@ -30,10 +40,10 @@ class Tokens extends Controller {
$expires = datetime_convert(date_default_timezone_get(),'UTC',$_POST['expires']);
else
$expires = NULL_DATE;
- $max_atokens = service_class_fetch(local_channel(),'access_tokens');
+ $max_atokens = service_class_fetch($channel['channel_id'],'access_tokens');
if($max_atokens) {
$r = q("select count(atoken_id) as total where atoken_uid = %d",
- intval(local_channel())
+ intval($channel['channel_id'])
);
if($r && intval($r[0]['total']) >= $max_tokens) {
notice( sprintf( t('This channel is limited to %d tokens'), $max_tokens) . EOL);
@@ -45,6 +55,17 @@ class Tokens extends Controller {
notice( t('Name and Password are required.') . EOL);
return;
}
+
+ $old_atok = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'",
+ intval($channel['channel_id']),
+ dbesc($name)
+ );
+
+ if ($old_atok) {
+ $old_atok = $old_atok[0];
+ $old_xchan = atoken_xchan($old_atok);
+ }
+
if($atoken_id) {
$r = q("update atoken set atoken_name = '%s', atoken_token = '%s', atoken_expires = '%s'
where atoken_id = %d and atoken_uid = %d",
@@ -56,8 +77,9 @@ class Tokens extends Controller {
);
}
else {
- $r = q("insert into atoken ( atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires )
- values ( %d, %d, '%s', '%s', '%s' ) ",
+ $r = q("insert into atoken (atoken_guid, atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires )
+ values ('%s', %d, %d, '%s', '%s', '%s' ) ",
+ dbesc($atoken_guid),
intval($channel['channel_account_id']),
intval($channel['channel_id']),
dbesc($name),
@@ -66,21 +88,85 @@ class Tokens extends Controller {
);
}
- $atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $name;
+ $atok = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'",
+ intval($channel['channel_id']),
+ dbesc($name)
+ );
- $all_perms = \Zotlabs\Access\Permissions::Perms();
+ if ($atok) {
+ $xchan = atoken_xchan($atok[0]);
+ atoken_create_xchan($xchan);
+ $atoken_xchan = $xchan['xchan_hash'];
+ if ($old_atok && $old_xchan) {
+ $r = q("update xchan set xchan_name = '%s' where xchan_hash = '%s'",
+ dbesc($xchan['xchan_name']),
+ dbesc($old_xchan['xchan_hash'])
+ );
+ }
+ }
- if($all_perms) {
- foreach($all_perms as $perm => $desc) {
- if(array_key_exists('perms_' . $perm, $_POST)) {
- set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,intval($_POST['perms_' . $perm]));
- }
- else {
- set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,0);
+
+ if (! $atoken_id) {
+
+ // If this is a new token, create a new abook record
+
+ $closeness = get_pconfig($uid,'system','new_abook_closeness',80);
+ $profile_assign = get_pconfig($uid,'system','profile_assign','');
+
+ $r = abook_store_lowlevel(
+ [
+ 'abook_account' => $channel['channel_account_id'],
+ 'abook_channel' => $channel['channel_id'],
+ 'abook_closeness' => intval($closeness),
+ 'abook_xchan' => $atoken_xchan,
+ 'abook_profile' => $profile_assign,
+ 'abook_feed' => 0,
+ 'abook_created' => datetime_convert(),
+ 'abook_updated' => datetime_convert(),
+ 'abook_instance' => z_root(),
+ ]
+ );
+
+ if (! $r) {
+ logger('abook creation failed');
+ }
+
+ /** If there is a default group for this channel, add this connection to it */
+
+ if ($channel['channel_default_group']) {
+ $g = AccessList::by_hash($uid,$channel['channel_default_group']);
+ if ($g) {
+ AccessList::member_add($uid,'',$atoken_xchan,$g['id']);
}
}
}
+ $role = ((array_key_exists('permcat', $_POST)) ? escape_tags($_POST['permcat']) : '');
+ \Zotlabs\Lib\Permcat::assign($channel, $role, [$atoken_xchan]);
+
+ $r = q("SELECT abook.*, xchan.*
+ FROM abook left join xchan on abook_xchan = xchan_hash
+ WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1",
+ intval($channel['chnnel_id']),
+ dbesc($atoken_xchan)
+ );
+
+ if (! $r) {
+ return;
+ }
+
+ $clone = $r[0];
+
+ unset($clone['abook_id']);
+ unset($clone['abook_account']);
+ unset($clone['abook_channel']);
+
+ $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
+ if ($abconfig) {
+ $clone['abconfig'] = $abconfig;
+ }
+
+ Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => [ $clone ], 'atoken' => $atok ], true);
info( t('Token saved.') . EOL);
return;
@@ -103,6 +189,7 @@ class Tokens extends Controller {
$atoken = null;
$atoken_xchan = '';
+ $atoken_abook = [];
if(argc() > 1) {
$id = argv(1);
@@ -114,13 +201,47 @@ class Tokens extends Controller {
if($atoken) {
$atoken = $atoken[0];
- $atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $atoken['atoken_name'];
+ $atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $atoken['atoken_guid'];
+
+ $atoken_abook = q("select * from abook where abook_channel = %d and abook_xchan = '%s'",
+ intval(local_channel()),
+ dbesc($atoken_xchan)
+ );
+
+ $atoken_abook = $atoken_abook[0];
}
if($atoken && argc() > 2 && argv(2) === 'drop') {
+ $atoken['deleted'] = true;
+
+ $r = q("SELECT abook.*, xchan.*
+ FROM abook left join xchan on abook_xchan = xchan_hash
+ WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1",
+ intval($channel['chnnel_id']),
+ dbesc($atoken_xchan)
+ );
+ if (! $r) {
+ return;
+ }
+
+ $clone = $r[0];
+
+ unset($clone['abook_id']);
+ unset($clone['abook_account']);
+ unset($clone['abook_channel']);
+ $clone['deleted'] = true;
+
+ $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
+ if ($abconfig) {
+ $clone['abconfig'] = $abconfig;
+ }
+
atoken_delete($id);
+ Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => [ $clone ], 'atoken' => [ $atoken ] ], true);
+
$atoken = null;
$atoken_xchan = '';
+ $atoken_abook = null;
}
}
@@ -132,39 +253,34 @@ class Tokens extends Controller {
$desc2 = t('You may also provide <em>dropbox</em> style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:');
- $global_perms = \Zotlabs\Access\Permissions::Perms();
- $their_perms = [];
- $existing = get_all_perms(local_channel(),(($atoken_xchan) ? $atoken_xchan : ''),false);
+ //TODO: assign role
+ $pcat = new Permcat(local_channel());
+ $pcatlist = $pcat->listing();
+ $default_role = get_pconfig(local_channel(), 'system', 'default_permcat');
+ $current_permcat = (($atoken_abook) ? $atoken_abook['abook_role'] : $default_role);
- if($atoken_xchan) {
- $theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'",
- intval(local_channel()),
- dbesc($atoken_xchan)
- );
- if($theirs) {
- foreach($theirs as $t) {
- $their_perms[$t['k']] = $t['v'];
- }
- }
+ $roles_dict = [];
+ foreach ($pcatlist as $role) {
+ $roles_dict[$role['name']] = $role['localname'];
}
- foreach($global_perms as $k => $v) {
- $thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k);
-//fixme
-
- $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k);
- if($existing[$k])
- $thisperm = "1";
- $perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited);
+ if (!$current_permcat) {
+ notice(t('Please select a role for this contact!') . EOL);
+ $permcats[] = '';
}
-
+ if ($pcatlist) {
+ foreach ($pcatlist as $pc) {
+ $permcats[$pc['name']] = $pc['localname'];
+ }
+ }
$tpl = get_markup_template("tokens.tpl");
$o .= replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("tokens"),
+ '$permcat' => ['permcat', t('Select a role for this token'), $current_permcat, '', $permcats],
'$title' => t('Guest Access Tokens'),
'$desc' => $desc,
'$desc2' => $desc2,
diff --git a/boot.php b/boot.php
index 838c93177..91f0b8147 100644
--- a/boot.php
+++ b/boot.php
@@ -58,7 +58,7 @@ define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '6.5.10' );
define ( 'ZOT_REVISION', '6.0' );
-define ( 'DB_UPDATE_VERSION', 1249 );
+define ( 'DB_UPDATE_VERSION', 1250 );
define ( 'PROJECT_BASE', __DIR__ );
diff --git a/include/channel.php b/include/channel.php
index 00d973738..c80a35385 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -21,6 +21,7 @@ require_once('include/crypto.php');
require_once('include/menu.php');
require_once('include/perm_upgrade.php');
require_once('include/photo/photo_driver.php');
+require_once('include/security.php');
/**
* @brief Called when creating a new channel.
@@ -878,6 +879,14 @@ function identity_basic_export($channel_id, $sections = null, $zap_compat = fals
}
if(in_array('connections',$sections)) {
+ $r = q("select * from atoken where atoken_uid = %d",
+ intval($channel_id)
+ );
+
+ if ($r) {
+ $ret['atoken'] = $r;
+ }
+
$xchans = array();
$r = q("select * from abook where abook_channel = %d ",
intval($channel_id)
@@ -1963,11 +1972,24 @@ function zat_init() {
);
if($r) {
$xchan = atoken_xchan($r[0]);
- atoken_create_xchan($xchan);
+ //atoken_create_xchan($xchan);
atoken_login($xchan);
}
}
+function atoken_delete_and_sync($channel_id, $atoken_guid) {
+ $r = q("select * from atoken where atoken_guid = '%s' and atoken_uid = %d",
+ dbesc($atoken_guid),
+ intval($channel_id)
+ );
+
+ if ($r) {
+ $atok = $r[0];
+ $atok['deleted'] = true;
+ atoken_delete($atok['atoken_id']);
+ Libsync::build_sync_packet($channel_id, ['atoken' => [ $atok ]]);
+ }
+}
/**
* @brief Used from within PCSS themes to set theme parameters.
diff --git a/include/connections.php b/include/connections.php
index 11264e6d8..fbbf59c72 100644
--- a/include/connections.php
+++ b/include/connections.php
@@ -376,6 +376,19 @@ function contact_remove($channel_id, $abook_id) {
if(intval($abook['abook_self']))
return false;
+ // if this is an atoken, delete the atoken record
+
+ $xchan = q("select * from xchan where xchan_hash = '%s'",
+ dbesc($abook['abook_xchan'])
+ );
+
+ if (strpos($xchan['xchan_addr'],'guest:') === 0 && strpos($abook['abook_xchan'],'.')){
+ $atoken_guid = substr($abook['abook_xchan'],strrpos($abook['abook_xchan'],'.') + 1);
+ if ($atoken_guid) {
+ atoken_delete_and_sync($channel_id,$atoken_guid);
+ }
+ }
+
$r = q("select id, parent from item where (owner_xchan = '%s' or author_xchan = '%s') and uid = %d and item_retained = 0 and item_starred = 0",
dbesc($abook['abook_xchan']),
dbesc($abook['abook_xchan']),
diff --git a/include/import.php b/include/import.php
index 8707a9430..291dd2638 100644
--- a/include/import.php
+++ b/include/import.php
@@ -162,6 +162,64 @@ function import_config($channel, $configs) {
}
}
+function import_atoken($channel, $atokens) {
+ if ($channel && $atokens) {
+ foreach ($atokens as $atoken) {
+ unset($atoken['atoken_id']);
+ $atoken['atoken_aid'] = $channel['channel_account_id'];
+ $atoken['atoken_uid'] = $channel['channel_id'];
+ create_table_from_array('atoken', $atoken);
+ }
+ }
+}
+
+function sync_atoken($channel, $atokens) {
+
+ if ($channel && $atokens) {
+ foreach ($atokens as $atoken) {
+ unset($atoken['atoken_id']);
+ $atoken['atoken_aid'] = $channel['channel_account_id'];
+ $atoken['atoken_uid'] = $channel['channel_id'];
+
+ if ($atoken['deleted']) {
+ q("delete from atoken where atoken_uid = %d and atoken_guid = '%s' ",
+ intval($atoken['atoken_uid']),
+ dbesc($atoken['atoken_guid'])
+ );
+ continue;
+ }
+
+ $r = q("select * from atoken where atoken_uid = %d and atoken_guid = '%s' ",
+ intval($atoken['atoken_uid']),
+ dbesc($atoken['atoken_guid'])
+ );
+ if (! $r) {
+ create_table_from_array('atoken', $atoken);
+ }
+ else {
+ $columns = db_columns('atoken');
+ foreach ($atoken as $k => $v) {
+ if (! in_array($k,$columns)) {
+ continue;
+ }
+
+ if (in_array($k, ['atoken_guid','atoken_uid','atoken_aid'])) {
+ continue;
+ }
+
+ $r = q("UPDATE atoken SET " . TQUOT . "%s" . TQUOT . " = '%s' WHERE atoken_guid = '%s' AND atoken_uid = %d",
+ dbesc($k),
+ dbesc($v),
+ dbesc($atoken['atoken_guid']),
+ intval($channel['channel_id'])
+ );
+ }
+ }
+ }
+ }
+}
+
+
/**
* @brief Import profiles.
*
diff --git a/include/security.php b/include/security.php
index b6c0f1511..f02fb8023 100644
--- a/include/security.php
+++ b/include/security.php
@@ -89,8 +89,20 @@ function authenticate_success($user_record, $channel = null, $login_initial = fa
}
function atoken_login($atoken) {
- if (!$atoken)
+ if (! $atoken) {
return false;
+ }
+
+ if (App::$cmd === 'channel' && argv(1)) {
+ $channel = channelx_by_nick(argv(1));
+ if (perm_is_allowed($channel['channel_id'],$atoken['xchan_hash'],'delegate')) {
+ $_SESSION['delegate_channel'] = $channel['channel_id'];
+ $_SESSION['delegate'] = $atoken['xchan_hash'];
+ $_SESSION['account_id'] = intval($channel['channel_account_id']);
+ change_channel($channel['channel_id']);
+ return;
+ }
+ }
$_SESSION['authenticated'] = 1;
$_SESSION['visitor_id'] = $atoken['xchan_hash'];
@@ -113,11 +125,11 @@ function atoken_xchan($atoken) {
if ($c) {
return [
'atoken_id' => $atoken['atoken_id'],
- 'xchan_hash' => substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_name'],
+ 'xchan_hash' => substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_guid'],
'xchan_name' => $atoken['atoken_name'],
'xchan_addr' => 'guest:' . $atoken['atoken_name'] . '@' . App::get_hostname(),
'xchan_network' => 'unknown',
- 'xchan_url' => z_root() . '/guest/' . substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_name'],
+ 'xchan_url' => z_root() . '/guest/' . substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_guid'],
'xchan_hidden' => 1,
'xchan_photo_mimetype' => 'image/png',
'xchan_photo_l' => z_root() . '/' . get_default_profile_photo(300),
@@ -143,11 +155,17 @@ function atoken_delete($atoken_id) {
if (!$c)
return;
- $atoken_xchan = substr($c[0]['channel_hash'], 0, 16) . '.' . $r[0]['atoken_name'];
+ $atoken_xchan = substr($c[0]['channel_hash'], 0, 16) . '.' . $r[0]['atoken_guid'];
q("delete from atoken where atoken_id = %d",
intval($atoken_id)
);
+
+ q("delete from abook where abook_channel = %d and abook_xchan = '%s'",
+ intval($c[0]['channel_id']),
+ dbesc($atoken_xchan)
+ );
+
q("delete from abconfig where chan = %d and xchan = '%s'",
intval($c[0]['channel_id']),
dbesc($atoken_xchan)
@@ -198,7 +216,7 @@ function atoken_abook($uid, $xchan_hash) {
if (!$r)
return false;
- $x = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'",
+ $x = q("select * from atoken where atoken_uid = %d and atoken_guid = '%s'",
intval($uid),
dbesc(substr($xchan_hash, 17))
);
diff --git a/include/text.php b/include/text.php
index b2b3fce6e..84f112802 100644
--- a/include/text.php
+++ b/include/text.php
@@ -1715,7 +1715,7 @@ function prepare_body(&$item,$attach = false,$opts = false) {
if ($is_photo) {
$object = json_decode($item['obj'],true);
$ptr = null;
- if (array_key_exists('url',$object) && is_array($object['url'])) {
+ if (is_array($object) && array_key_exists('url',$object) && is_array($object['url'])) {
if (array_key_exists(0,$object['url'])) {
foreach ($object['url'] as $link) {
if(array_key_exists('width',$link) && $link['width'] >= 640 && $link['width'] <= 1024) {
diff --git a/install/schema_mysql.sql b/install/schema_mysql.sql
index 054c1da03..80ae20d7b 100644
--- a/install/schema_mysql.sql
+++ b/install/schema_mysql.sql
@@ -148,12 +148,14 @@ CREATE TABLE IF NOT EXISTS `app` (
CREATE TABLE IF NOT EXISTS `atoken` (
`atoken_id` int(11) NOT NULL AUTO_INCREMENT,
+ `atoken_guid` char(191) NOT NULL DEFAULT '',
`atoken_aid` int(11) NOT NULL DEFAULT 0 ,
`atoken_uid` int(11) NOT NULL DEFAULT 0 ,
`atoken_name` char(191) NOT NULL DEFAULT '',
`atoken_token` char(191) NOT NULL DEFAULT '',
`atoken_expires` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY (`atoken_id`),
+ KEY `atoken_guid` (`atoken_guid`),
KEY `atoken_aid` (`atoken_aid`),
KEY `atoken_uid` (`atoken_uid`),
KEY `atoken_uid_2` (`atoken_uid`),
diff --git a/install/schema_postgres.sql b/install/schema_postgres.sql
index c1cbc832b..96d0cc33c 100644
--- a/install/schema_postgres.sql
+++ b/install/schema_postgres.sql
@@ -147,12 +147,14 @@ create index "app_system" on app ("app_system");
CREATE TABLE "atoken" (
"atoken_id" serial NOT NULL,
+ "atoken_guid" varchar(255) NOT NULL DEFAULT '',
"atoken_aid" bigint NOT NULL DEFAULT 0,
"atoken_uid" bigint NOT NULL DEFAULT 0,
"atoken_name" varchar(255) NOT NULL DEFAULT '',
"atoken_token" varchar(255) NOT NULL DEFAULT '',
"atoken_expires" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY ("atoken_id"));
+create index atoken_guid on atoken (atoken_guid);
create index atoken_aid on atoken (atoken_aid);
create index atoken_uid on atoken (atoken_uid);
create index atoken_name on atoken (atoken_name);
diff --git a/view/tpl/tokens.tpl b/view/tpl/tokens.tpl
index 6bf8dc202..51cd4a6cf 100644
--- a/view/tpl/tokens.tpl
+++ b/view/tpl/tokens.tpl
@@ -14,12 +14,14 @@
{{include file="field_input.tpl" field=$name}}
{{include file="field_input.tpl" field=$token}}
{{include file="field_input.tpl" field=$expires}}
+ {{include file="field_select.tpl" field=$permcat}}
+
<div class="settings-submit-wrapper mb-3">
<button type="submit" name="submit" class="btn btn-primary">{{$submit}}</button>
</div>
</div>
- <div class="panel" id="permission-settings">
+ <!--div class="panel" id="permission-settings">
<div class="section-subtitle-wrapper" role="tab" id="perms-tool">
<h3>
<a data-bs-toggle="collapse" data-bs-parent="#permission-settings" href="#perms-tool-collapse" aria-expanded="true" aria-controls="perms-tool-collapse">
@@ -47,8 +49,7 @@
</div>
</div>
</div>
- </div>
- </form>
+ </div-->
<div class="descriptive-text">{{$desc2}}</div>
<ul>