Handle power levels configuration in room-modify

tags/patrix-0.1.4-1
Daniel Berteaud 7 years ago
parent 78d5dc25bc
commit 0a7b73403f
  1. 23
      README.md
  2. 1
      TODO
  3. 2
      patrix.spec
  4. 97
      scripts/patrix

@ -12,6 +12,8 @@ It requires the following perl modules
* URI::Escape
* JSON
* Term::ReadKey
* Hash::Merge::Simple
* Scalar::Util
Here're the vailable options:
@ -29,6 +31,10 @@ Here're the vailable options:
* --topic: set the topic of a room. Valid for create-room and modify-room
* --alias: set an alias for a room. Valid for create-room and modify-room
* --join_rules: change joining rules. Can be either public (anyone can join the room) or invite (you must be invited to join the room)
* --perm: set power levels on the room. Can be specified several times. See examples
* --perm_user: set user levels on the room. Can be specified several times. See examples
* --perm_event: set power levels requires to send specific state events. Can be specified several times. See examples
* --perm_reset: the default behavior of the various --perm args is to add or override specific permissions without changing the others already existing permission. If this flag is set, the previous permissions will be removed, and the one specified with the --perm arg will be applied. The only exception is for user power levels which are at least as high as the operator (including the operator). These user power levels will be kept even is --perm-reset is set
* --federation: Enable the federation when creating a room. Default is enabled. Can be turned of with --no-federation
* --action: what to do. Valid actions are
* send-msg (default): send the text message
@ -53,18 +59,35 @@ Options given on the command line take precedence over the config file
Examples:
* Send the content of /var/log/boot.log to a room (as text)
```
cat /var/log/boot.log | patrix --room='#bootlogs:matrix.domain.com' --action=send-notice
```
* Send a file (here, the room name must be specified in the config file)
```
patrix --action=send-file --file=/home/dani/archive.tgz --user=dani --password=secret --server=matrix.domain.com
```
* Send a simple text message, and enable debuging
```
patrix --debug --message="Hello World"
```
* Create a new room, set its name and invite a Matrix user
```
patrix --action=create-room --name="Human readable room name" --invite="@dani:matrix.example.com"
```
* Configure an existing room
```
patrix --action=modify-room --join_rules=public --topic='New topic' --room='!uXfknaWNcAnvthnIms:matrix.example.com' --invite='@admin:matrix.example.com'
```
* Change power level needed for the ban action. Set the default power levels of new users to 10. Set power level for @dani:matrix.example.com to 90
```
patrix --action=modify-room --perm "ban=70" --perm "users_default=10" --perm_user "@dani:matrix.example.com=90"
```
* Set the required power level to send the m.room.name event to 80 (you can change the room name if you have a power level of at least 80)
```
patrix --action=modify-room --perm_event "m.room.name=80"
```
* Reset permissions. Only keep user power levels which are at least the same as yours (including yours)
```
patrix --action=modify-room --perm_reset
```

@ -1,4 +1,3 @@
* Set power levels
* Purge history of a room
* Purge history of all empty rooms (with no members)
* Modify federation setting of a room

@ -20,6 +20,8 @@ Requires: perl(File::MimeInfo)
Requires: perl(Path::Tiny)
Requires: perl(URI::Escape)
Requires: perl(Term::ReadKey)
Requires: perl(Hash::Merge::Simple)
Requires: perl(Scalar::Util)
%description
Patrix is a simple (and quite limited) client for the Matrix communication network

@ -13,7 +13,8 @@ use File::Basename;
use URI::Escape;
use Path::Tiny;
use Term::ReadKey;
use Data::Dumper;
use Hash::Merge::Simple qw(merge);
use Scalar::Util qw(looks_like_number);
our $opt;
@ -33,7 +34,11 @@ GetOptions(
"alias=s" => \$opt->{alias},
"topic=s" => \$opt->{topic},
"join_rules=s" => \$opt->{join_rules},
"federation!" => \$opt->{federation}
"federation!" => \$opt->{federation},
"perm=s@" => \$opt->{perm},
"perm_user=s@" => \$opt->{perm_user},
"perm_event=s@" => \$opt->{perm_user},
"perm_reset" => \$opt->{perm_reset}
);
if (-e File::HomeDir->my_home . "/.patrixrc" && !$opt->{conf}){
@ -58,7 +63,9 @@ $opt->{action} //= 'send-msg';
$opt->{federation} //= 1;
$opt->{server} = 'https://' . $opt->{server} unless ($opt->{server} =~ m|https?://|);
# Prompt to enter the password
# No password on the command line or the conf file
# And no access token
# Prompt to type the password
if (!$opt->{access_token} && $opt->{user} && !$opt->{password}){
ReadMode('noecho');
print "Password: ";
@ -68,6 +75,8 @@ if (!$opt->{access_token} && $opt->{user} && !$opt->{password}){
print "\n";
}
# If the given room starts with #, then it's an alias
# Lets resolve this to the room ID
if ($opt->{room} && $opt->{room} =~ m/^#/){
$opt->{room} = room_alias_to_id($opt->{room});
debug('Room ID is ' . $opt->{room});
@ -178,6 +187,27 @@ sub join_room {
die "Error joining room $opt->{room}\n" unless ($resp->is_success);
}
# Retrieve the actual permissions for a room
sub get_room_permissions {
debug('Getting actual room state');
my $uri = $opt->{server} . '/_matrix/client/r0/rooms/' . $opt->{room} . '/state/m.room.power_levels?access_token=' . $opt->{access_token};
my $resp = send_request({
method => 'GET',
uri => $uri
});
die "Error joining room $opt->{room}\n" unless ($resp->is_success);
return from_json($resp->decoded_content);
}
# Return the user ID of the operator
sub who_am_i {
# We could get user_id if we login with user/pass but what if we use an access token ?
# Lets just build it manually for now
my $server = $opt->{server};
$server =~ s|^https?://||;
return '@' . $opt->{user} .':' . $server;
}
# Send a text message (either message or notice as both are similar)
sub send_msg {
my $uri = $opt->{server} . '/_matrix/client/r0/rooms/' . $opt->{room} . '/send/m.room.message?access_token=' . $opt->{access_token};
@ -336,6 +366,67 @@ sub modify_room {
die "Error changing joining rules of room $opt->{room}\n"
unless ($resp->is_success);
}
# Permissions modification
if ($opt->{perm} || $opt->{perm_user} || $opt->{perm_event} || $opt->{perm_reset}){
debug('Changing permissions for the room');
my $current_perm = get_room_permissions();
# If we asked to reset the permission
if ($opt->{perm_reset}){
my $operator = who_am_i();
my $reset_perm = {
events => {
"m.room.avatar" => 50,
"m.room.canonical_alias" => 50,
"m.room.name" => 50,
"m.room.power_levels" => 100,
"m.room.history_visibility" => 100
},
};
# Ensure we keep at least the permission of the operating user
# Note that we must also keep the permission of anyone who has at least the same level
# of privilege, or the operation will be forbidden
foreach my $user (keys %{$current_perm->{users}}){
if (looks_like_number($current_perm->{users}->{$user}) &&
$current_perm->{users}->{$user} >= $current_perm->{users}->{$operator}){
debug("Keeping permission of $user because it has at least the same privileges " .
"($current_perm->{users}->{$user} vs $current_perm->{users}->{$operator})");
$reset_perm->{users}->{$user} = $current_perm->{users}->{$user};
}
}
$current_perm = $reset_perm;
}
my $new_perm = {};
if ($opt->{perm}){
foreach my $perm (@{$opt->{perm}}){
my ($key,$val) = split (/\s*=\s*/, $perm);
$new_perm->{$key} = $val;
}
}
if ($opt->{perm_user}){
foreach my $perm (@{$opt->{perm_user}}){
my ($key,$val) = split (/\s*=\s*/, $perm);
# Prevent the operating user to downgrade its own permissions
next if ($key eq $opt->{user});
$new_perm->{users}->{$key} = $val;
}
}
if ($opt->{perm_event}){
foreach my $perm (@{$opt->{perm_event}}){
my ($key,$val) = split (/\s*=\s*/, $perm);
$new_perm->{events}->{$key} = $val;
}
}
my $perm = merge($current_perm, $new_perm);
print to_json($perm, { pretty => 1 });
$uri = $opt->{server} . '/_matrix/client/r0/rooms/' . $opt->{room} . '/state/m.room.power_levels?access_token=' . $opt->{access_token};
$resp = send_request({
method => 'PUT',
uri => $uri,
content => to_json($perm)
});
die "Error changing permissions for room $opt->{room}\n"
unless ($resp->is_success);
}
# New invitees should be added
if ($opt->{invite}){
debug('Inviting ' . join(',', @{$opt->{invite}}) . ' to join the room');

Loading…
Cancel
Save