Matrix.pm 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package Trog::Authz::Matrix;
  2. use strict;
  3. use warnings;
  4. no warnings 'experimental';
  5. use feature qw{signatures state};
  6. use parent 'Trog::Authz::Base';
  7. use Trog::Auth ();
  8. use HTTP::Tiny ();
  9. use constant 'required_params' => [ 'extAuthData' ];
  10. sub do_auth ($self) {
  11. die "Please setup an admin user first" if !$self->{'params'}{'hasusers'};
  12. $self->failed(1);
  13. require JSON::XS;
  14. my $decoded;
  15. eval { $decoded = JSON::XS::decode_json($self->{'params'}{'extAuthData'}); };
  16. return $self if !$decoded;
  17. # XXX TODO potential security/DOS issue -- How does one prevent spoofing on this end?
  18. # For example, user POSTs the json blob with the right param names, etc. but no
  19. # actual auth gating -- Suddenly you have a user and session more or less out of
  20. # whole cloth with no auth ever done. Only thing I can think of to prevent this
  21. # is more or less "after the fact" via calling `isSignedIn()` as part of pageload
  22. # when you are a matrix user, invalidating the session if not.
  23. # I'm sure you can already tell the hole in this perfect plan -- "just disable js".
  24. # The only real way I can think of for now to prevent abuse here is to do a check
  25. # on the backend using the access token and user just to do some kind of ping check.
  26. # That said this still just makes it "harder" to pull off bullshit. Only way to be
  27. # 100% sure we are talking to a matrix server would be to do it all on the backend.
  28. # That said, this is probably "good enough" for now.
  29. my $ping_url = $decoded->{'well_known'}{'m.homeserver'}{'base_url'};
  30. $ping_url .= "/_matrix/client/r0/presence/$decoded->{'user_id'}/status";
  31. $ping_url .= "?access_token=$decoded->{'access_token'}";
  32. my $resp = HTTP::Tiny->new->get($ping_url);
  33. return $self unless $resp->{'success'};
  34. # I'm using ACLs here as a proxy for the user existing.
  35. # That may? be a bad assumption. If so I need to make another sub for getting this.
  36. my @acls = Trog::Auth::acls4user($decoded->{user_id});
  37. if(!@acls) {
  38. # Create the user XXX TODO -- Have a config param for "extra" ACLs the admin
  39. # can assign in the UI/Config in order to give them other "default" ACLs like
  40. # access to private content or ability to comment on articles, etc.
  41. my $cfg = Trog::Config::get();
  42. Trog::Auth::useradd(
  43. $decoded->{user_id},
  44. 'Matrix', # Never used here, so just put in the ext auth provider name.
  45. [ 'extAuthUser' ], # This ACL is important, and should be non-removable.
  46. );
  47. # By default, the avatar is cropped to 20x20, let's get a larger one if available.
  48. my $avatar_url = substr( $decoded->{avatar_content}, 0, index( $decoded->{'avatar_content'}, '?' ) );
  49. $avatar_url .= "?height=120&width=120&method=crop";
  50. my $dat = Trog::Data->new($cfg);
  51. $dat->add(
  52. {
  53. title => $decoded->{user_id},
  54. data => $decoded->{displayname},
  55. preview => $avatar_url,
  56. wallpaper => '/img/sys/testpattern.jpg',
  57. tags => ['about'],
  58. visibility => 'public',
  59. acls => ['admin'],
  60. local_href => "/users/$decoded->{user_id}",
  61. callback => "Trog::Routes::HTML::users",
  62. method => 'GET',
  63. user => $decoded->{user_id},
  64. form => 'profile.tx',
  65. aliases => [],
  66. },
  67. );
  68. }
  69. # Check if banned
  70. return $self if grep { $_ eq 'banned' } @acls;
  71. my $cookie = Trog::Auth::mksession( $decoded->{user_id}, 'Matrix' );
  72. $self->handle_cookie($cookie);
  73. $self->failed(0);
  74. return $self;
  75. }
  76. 1;