git: 7758d0b88dd4 - main - www/rt50: Update to 5.0.5
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 07 Nov 2023 12:13:56 UTC
The branch main has been updated by mikael:
URL: https://cgit.FreeBSD.org/ports/commit/?id=7758d0b88dd4874449e3e708a41867c0f43bb3fd
commit 7758d0b88dd4874449e3e708a41867c0f43bb3fd
Author: Mikael Urankar <mikael@FreeBSD.org>
AuthorDate: 2023-10-20 09:31:06 +0000
Commit: Mikael Urankar <mikael@FreeBSD.org>
CommitDate: 2023-11-07 12:13:51 +0000
www/rt50: Update to 5.0.5
Changes:
https://github.com/bestpractical/rt/releases/tag/rt-5.0.5
PR: 274607
---
www/rt50/Makefile | 3 +-
www/rt50/Makefile.cpan | 4 +-
www/rt50/distinfo | 6 +-
www/rt50/files/patch-vuln-2023-09-26 | 1118 ----------------------------------
www/rt50/pkg-plist | 14 +
5 files changed, 20 insertions(+), 1125 deletions(-)
diff --git a/www/rt50/Makefile b/www/rt50/Makefile
index 09b2f7c61d04..f9744f86b531 100644
--- a/www/rt50/Makefile
+++ b/www/rt50/Makefile
@@ -1,6 +1,5 @@
PORTNAME= rt
-DISTVERSION= 5.0.4
-PORTREVISION= 1
+DISTVERSION= 5.0.5
CATEGORIES= www
MASTER_SITES= http://download.bestpractical.com/pub/rt/release/
PKGNAMESUFFIX= 50
diff --git a/www/rt50/Makefile.cpan b/www/rt50/Makefile.cpan
index 6ef8033d17a9..74a087466bb9 100644
--- a/www/rt50/Makefile.cpan
+++ b/www/rt50/Makefile.cpan
@@ -22,7 +22,7 @@
### DateTime::Format::Natural 0.67
### DateTime::Locale 0.40
### DBI 1.37
-### DBIx::SearchBuilder 1.76
+### DBIx::SearchBuilder 1.77
### Devel::GlobalDestruction
### Devel::StackTrace 1.19
### Digest::base perl std
@@ -104,7 +104,7 @@ CORE_DEPS= p5-Apache-Session>=1.53:www/p5-Apache-Session \
p5-Convert-Color>0:graphics/p5-Convert-Color \
p5-Crypt-Eksblowfish>0:security/p5-Crypt-Eksblowfish \
p5-DBI>=1.37:databases/p5-DBI \
- p5-DBIx-SearchBuilder>=1.76:databases/p5-DBIx-SearchBuilder \
+ p5-DBIx-SearchBuilder>=1.77:databases/p5-DBIx-SearchBuilder \
p5-Data-GUID>0:devel/p5-Data-GUID \
p5-Data-ICal>0:deskutils/p5-Data-ICal \
p5-Data-Page>0:databases/p5-Data-Page \
diff --git a/www/rt50/distinfo b/www/rt50/distinfo
index 0bfa784c4625..e0d4d8f8282b 100644
--- a/www/rt50/distinfo
+++ b/www/rt50/distinfo
@@ -1,3 +1,3 @@
-TIMESTAMP = 1683267561
-SHA256 (rt-5.0.4.tar.gz) = 916d870d22d92027f843798be6f880aaf1517aebc3f6ab25f456f4e772f4834d
-SIZE (rt-5.0.4.tar.gz) = 18949618
+TIMESTAMP = 1697786825
+SHA256 (rt-5.0.5.tar.gz) = 90f845daaa436198c334b6e9cf5afb1df9f4445dcc165d0bcae35de9eb9be8ef
+SIZE (rt-5.0.5.tar.gz) = 19055361
diff --git a/www/rt50/files/patch-vuln-2023-09-26 b/www/rt50/files/patch-vuln-2023-09-26
deleted file mode 100644
index 83e7ddf5b63b..000000000000
--- a/www/rt50/files/patch-vuln-2023-09-26
+++ /dev/null
@@ -1,1118 +0,0 @@
-The following issues are addressed with these security updates:
-
- RT is vulnerable to unvalidated email headers in incoming email and the mail-gateway REST interface. This vulnerability is assigned CVE-2023-41259.
- RT is vulnerable to information leakage via response messages returned from requests sent via the mail-gateway REST interface. This vulnerability is assigned CVE-2023-41260.
- RT 5.0 is vulnerable to information leakage via transaction searches made by authenticated users in the transaction query builder. This vulnerability is assigned CVE-2023-45024.
- RT 5.0 can reveal information about data on various RT objects in errors and other response messages to REST 2 requests.
-
-diff --git a/docs/web_deployment.pod b/docs/web_deployment.pod
-index 6ee03d48d8..c22001103a 100644
---- docs/web_deployment.pod
-+++ docs/web_deployment.pod
-@@ -127,6 +127,31 @@ RT to access the Authorization header.
-
- More information is available in L<RT::Authen::Token>.
-
-+=head3 Restricting the REST 1.0 mail-gateway
-+
-+RT processes email via a REST 1.0 endpoint. If you accept email on the same
-+server as your running RT, you can restrict this endpoint to localhost only
-+with a configuration like the following:
-+
-+ # Accept requests only from localhost
-+ <Location /REST/1.0/NoAuth/mail-gateway>
-+ Require local
-+ </Location>
-+
-+If you run C<bin/rt-mailgate> on a separate server, you can update
-+the above to allow additional IP addresses.
-+
-+ <Location /REST/1.0/NoAuth/mail-gateway>
-+ Require ip 127.0.0.1 ::1 192.0.2.0 # Add you actual IPs
-+ </Location>
-+
-+See the L<Apache documentation|https://httpd.apache.org/docs/2.4/mod/mod_authz_host.html>
-+for additional configuration options.
-+
-+After adding this configuration, test receiving email and confirm
-+your C<bin/rt-mailgate> utility and C</etc/aliases> configurations
-+can successfully submit email to RT.
-+
- =head2 nginx
-
- C<nginx> requires that you start RT's fastcgi process externally, for
-diff --git a/lib/RT/Articles.pm b/lib/RT/Articles.pm
-index 79e771884e..787924ffff 100644
---- lib/RT/Articles.pm
-+++ lib/RT/Articles.pm
-@@ -970,6 +970,11 @@ sub SimpleSearch {
- return $self;
- }
-
-+sub CurrentUserCanSeeAll {
-+ my $self = shift;
-+ return $self->CurrentUser->HasRight( Right => 'ShowArticle', Object => RT->System ) ? 1 : 0;
-+}
-+
- RT::Base->_ImportOverlays();
-
- 1;
-diff --git a/lib/RT/Assets.pm b/lib/RT/Assets.pm
-index f6cf8ee647..516869f9cc 100644
---- lib/RT/Assets.pm
-+++ lib/RT/Assets.pm
-@@ -1932,6 +1932,11 @@ sub _ProcessRestrictions {
-
- }
-
-+sub CurrentUserCanSeeAll {
-+ my $self = shift;
-+ return $self->CurrentUser->HasRight( Right => 'ShowAsset', Object => RT->System ) ? 1 : 0;
-+}
-+
- 1;
-
- RT::Base->_ImportOverlays();
-diff --git a/lib/RT/Attachment.pm b/lib/RT/Attachment.pm
-index 2c50447a91..3fed08a360 100644
---- lib/RT/Attachment.pm
-+++ lib/RT/Attachment.pm
-@@ -1090,6 +1090,17 @@ sub _CacheConfig {
- }
-
-
-+=head2 CurrentUserCanSee
-+
-+Returns true if the current user can see the attachment, via corresponding
-+transaction's rights check.
-+
-+=cut
-+
-+sub CurrentUserCanSee {
-+ my $self = shift;
-+ return $self->TransactionObj->CurrentUserCanSee;
-+}
-
-
- =head2 id
-diff --git a/lib/RT/Catalog.pm b/lib/RT/Catalog.pm
-index 1354207523..31946435b1 100644
---- lib/RT/Catalog.pm
-+++ lib/RT/Catalog.pm
-@@ -297,6 +297,28 @@ sub CurrentUserCanSee {
- || $self->CurrentUserHasRight('AdminCatalog');
- }
-
-+=head2 CurrentUserCanCreate
-+
-+Returns true if the current user can create a new catalog, using I<AdminCatalog>.
-+
-+=cut
-+
-+sub CurrentUserCanCreate {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminCatalog');
-+}
-+
-+=head2 CurrentUserCanModify
-+
-+Returns true if the current user can modify the catalog, using I<AdminCatalog>.
-+
-+=cut
-+
-+sub CurrentUserCanModify {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminCatalog');
-+}
-+
- =head2 Owner
-
- Returns an L<RT::User> object for this catalog's I<Owner> role group. On error,
-diff --git a/lib/RT/Catalogs.pm b/lib/RT/Catalogs.pm
-index 250793c47b..6d67a47720 100644
---- lib/RT/Catalogs.pm
-+++ lib/RT/Catalogs.pm
-@@ -114,6 +114,11 @@ sub _Init {
-
- sub Table { "Catalogs" }
-
-+sub CurrentUserCanSeeAll {
-+ my $self = shift;
-+ return $self->CurrentUser->HasRight( Right => 'ShowCatalog', Object => RT->System ) ? 1 : 0;
-+}
-+
- RT::Base->_ImportOverlays();
-
- 1;
-diff --git a/lib/RT/Class.pm b/lib/RT/Class.pm
-index 01079040c0..03a7926cc2 100644
---- lib/RT/Class.pm
-+++ lib/RT/Class.pm
-@@ -507,6 +507,39 @@ sub IncludeArticleCFValue {
- return $self->{'_cf_include_hash'}{"Value-".$cfobj->Id};
- }
-
-+=head2 CurrentUserCanSee
-+
-+Returns true if the current user can see the class, using I<SeeClass>.
-+
-+=cut
-+
-+sub CurrentUserCanSee {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('SeeClass');
-+}
-+
-+=head2 CurrentUserCanCreate
-+
-+Returns true if the current user can create a new class, using I<AdminClass>.
-+
-+=cut
-+
-+sub CurrentUserCanCreate {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminClass');
-+}
-+
-+=head2 CurrentUserCanModify
-+
-+Returns true if the current user can modify the class, using I<AdminClass>.
-+
-+=cut
-+
-+sub CurrentUserCanModify {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminClass');
-+}
-+
- =head2 id
-
- Returns the current value of id.
-diff --git a/lib/RT/Classes.pm b/lib/RT/Classes.pm
-index ff446dddfb..9cac032d48 100644
---- lib/RT/Classes.pm
-+++ lib/RT/Classes.pm
-@@ -81,6 +81,11 @@ sub AddRecord {
-
- sub _SingularClass { "RT::Class" }
-
-+sub CurrentUserCanSeeAll {
-+ my $self = shift;
-+ return $self->CurrentUser->HasRight( Right => 'SeeClass', Object => RT->System ) ? 1 : 0;
-+}
-+
- RT::Base->_ImportOverlays();
-
- 1;
-diff --git a/lib/RT/CustomField.pm b/lib/RT/CustomField.pm
-index 79c1f1f5a5..e261eb6f8e 100644
---- lib/RT/CustomField.pm
-+++ lib/RT/CustomField.pm
-@@ -2072,6 +2072,28 @@ sub CurrentUserCanSee {
- return 0;
- }
-
-+=head2 CurrentUserCanCreate
-+
-+If the user has I<AdminCustomField> they can create a new custom field.
-+
-+=cut
-+
-+sub CurrentUserCanCreate {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminCustomField');
-+}
-+
-+=head2 CurrentUserCanModify
-+
-+If the user has I<AdminCustomField> they can modify the custom field.
-+
-+=cut
-+
-+sub CurrentUserCanModify {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminCustomField');
-+}
-+
- =head2 IncludeContentForValue [VALUE] (and SetIncludeContentForValue)
-
- Gets or sets the C<IncludeContentForValue> for this custom field. RT
-diff --git a/lib/RT/CustomFields.pm b/lib/RT/CustomFields.pm
-index 253513d0f9..0fc5569adb 100644
---- lib/RT/CustomFields.pm
-+++ lib/RT/CustomFields.pm
-@@ -475,6 +475,11 @@ sub LimitToCatalog {
- }
- }
-
-+sub CurrentUserCanSeeAll {
-+ my $self = shift;
-+ return $self->CurrentUser->HasRight( Right => 'SeeCustomField', Object => RT->System ) ? 1 : 0;
-+}
-+
- RT::Base->_ImportOverlays();
-
- 1;
-diff --git a/lib/RT/CustomRole.pm b/lib/RT/CustomRole.pm
-index ec37402925..750aaf2575 100644
---- lib/RT/CustomRole.pm
-+++ lib/RT/CustomRole.pm
-@@ -544,6 +544,28 @@ sub GroupType {
- return 'RT::CustomRole-' . $self->id;
- }
-
-+=head2 CurrentUserCanCreate
-+
-+Returns true if the current user can create a new custom role, using I<AdminCustomRoles>.
-+
-+=cut
-+
-+sub CurrentUserCanCreate {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminClass');
-+}
-+
-+=head2 CurrentUserCanModify
-+
-+Returns true if the current user can modify the custom role, using I<AdminCustomRoles>.
-+
-+=cut
-+
-+sub CurrentUserCanModify {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminClass');
-+}
-+
- =head2 id
-
- Returns the current value of id.
-diff --git a/lib/RT/CustomRoles.pm b/lib/RT/CustomRoles.pm
-index 6cac676858..75587c71ed 100644
---- lib/RT/CustomRoles.pm
-+++ lib/RT/CustomRoles.pm
-@@ -213,6 +213,12 @@ sub LimitToAdded {
- return RT::ObjectCustomRoles->new( $self->CurrentUser )->LimitTargetToAdded( $self => @_ );
- }
-
-+sub CurrentUserCanSeeAll {
-+ my $self = shift;
-+ # Not typo, user needs SeeQueue to see CustomRoles
-+ return $self->CurrentUser->HasRight( Right => 'SeeQueue', Object => RT->System ) ? 1 : 0;
-+}
-+
- RT::Base->_ImportOverlays();
-
- 1;
-diff --git a/lib/RT/Group.pm b/lib/RT/Group.pm
-index ccc92fe7c1..03e20eb707 100644
---- lib/RT/Group.pm
-+++ lib/RT/Group.pm
-@@ -1311,17 +1311,43 @@ sub _Set {
-
- =head2 CurrentUserCanSee
-
--Always returns 1; unfortunately, for historical reasons, users have
--always been able to examine groups they have indirect access to, even if
--they do not have SeeGroup explicitly.
-+Unfortunately, for historical reasons, users have always been able to
-+examine groups they have indirect access to, even if they do not have
-+SeeGroup explicitly.
-+
-+We do require "SeeGroup" to see transactions of current group.
-
- =cut
-
- sub CurrentUserCanSee {
- my $self = shift;
-- return 1;
-+ my ($what, $txn) = @_;
-+
-+ return 1 if ( $what // '' ) ne 'Transaction';
-+ return $self->CurrentUserHasRight('SeeGroup');
-+}
-+
-+=head2 CurrentUserCanCreate
-+
-+Returns true if the current user can create a new group, using I<AdminGroup>.
-+
-+=cut
-+
-+sub CurrentUserCanCreate {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminGroup');
- }
-
-+=head2 CurrentUserCanModify
-+
-+Returns true if the current user can modify the group, using I<AdminGroup>.
-+
-+=cut
-+
-+sub CurrentUserCanModify {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminGroup');
-+}
-
- =head2 PrincipalObj
-
-diff --git a/lib/RT/Groups.pm b/lib/RT/Groups.pm
-index 2f341bbba3..51a43f95e3 100644
---- lib/RT/Groups.pm
-+++ lib/RT/Groups.pm
-@@ -537,6 +537,11 @@ sub SimpleSearch {
- return $self;
- }
-
-+sub CurrentUserCanSeeAll {
-+ my $self = shift;
-+ return $self->CurrentUser->HasRight( Right => 'SeeGroup', Object => RT->System ) ? 1 : 0;
-+}
-+
- RT::Base->_ImportOverlays();
-
- 1;
-diff --git a/lib/RT/Interface/Email.pm b/lib/RT/Interface/Email.pm
-index 39bd5c4169..648e0e7f61 100644
---- lib/RT/Interface/Email.pm
-+++ lib/RT/Interface/Email.pm
-@@ -161,6 +161,10 @@ sub Gateway {
- );
- }
-
-+ # Clean up sensitive headers. Crypt related headers are cleaned up in RT::Interface::Email::Crypt::VerifyDecrypt
-+ my @headers = qw( RT-Attach RT-Send-Cc RT-Send-Bcc RT-Message-ID RT-DetectedAutoGenerated RT-Squelch-Replies-To );
-+ $Message->head->delete($_) for @headers;
-+
- #Set up a queue object
- my $SystemQueueObj = RT::Queue->new( RT->SystemUser );
- $SystemQueueObj->Load( $args{'queue'} );
-diff --git a/lib/RT/Interface/Email/Crypt.pm b/lib/RT/Interface/Email/Crypt.pm
-index bc3427ca49..9d4d4fe584 100644
---- lib/RT/Interface/Email/Crypt.pm
-+++ lib/RT/Interface/Email/Crypt.pm
-@@ -73,13 +73,14 @@ sub VerifyDecrypt {
- );
-
- # we clean all possible headers
-- my @headers =
-+ my @headers = (
- qw(
- X-RT-Incoming-Encryption
- X-RT-Incoming-Signature X-RT-Privacy
- X-RT-Sign X-RT-Encrypt
- ),
-- map "X-RT-$_-Status", RT::Crypt->Protocols;
-+ map "X-RT-$_-Status", RT::Crypt->Protocols
-+ );
- foreach my $p ( $args{'Message'}->parts_DFS ) {
- $p->head->delete($_) for @headers;
- }
-diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
-index 444eb1c24e..da0ec92bf8 100644
---- lib/RT/Interface/Web.pm
-+++ lib/RT/Interface/Web.pm
-@@ -5792,6 +5792,28 @@ sub ParseCalendarData {
- return undef;
- }
-
-+sub PreprocessTransactionSearchQuery {
-+ my %args = (
-+ Query => undef,
-+ ObjectType => 'RT::Ticket',
-+ @_
-+ );
-+
-+ my @limits;
-+ if ( $args{ObjectType} eq 'RT::Ticket' ) {
-+ @limits = (
-+ q{TicketType = 'ticket'},
-+ qq{ObjectType = '$args{ObjectType}'},
-+ $args{Query} =~ /^\s*\(.*\)$/ ? $args{Query} : "($args{Query})"
-+ );
-+ }
-+ else {
-+ # Other ObjectTypes are not supported for now
-+ @limits = 'id = 0';
-+ }
-+ return join ' AND ', @limits;
-+}
-+
- package RT::Interface::Web;
- RT::Base->_ImportOverlays();
-
-diff --git a/lib/RT/ObjectCustomFieldValue.pm b/lib/RT/ObjectCustomFieldValue.pm
-index 53e62c2334..4815f76406 100644
---- lib/RT/ObjectCustomFieldValue.pm
-+++ lib/RT/ObjectCustomFieldValue.pm
-@@ -815,6 +815,7 @@ object, otherwise false.
-
- sub CurrentUserCanSee {
- my $self = shift;
-+ return undef unless $self->Id;
- return $self->CustomFieldObj->CurrentUserHasRight('SeeCustomField');
- }
-
-diff --git a/lib/RT/Queue.pm b/lib/RT/Queue.pm
-index 29ba7db3ad..609a7ebe5b 100644
---- lib/RT/Queue.pm
-+++ lib/RT/Queue.pm
-@@ -810,6 +810,29 @@ sub CurrentUserCanSee {
- return $self->CurrentUserHasRight('SeeQueue');
- }
-
-+
-+=head2 CurrentUserCanCreate
-+
-+Returns true if the current user can create a new queue, using I<AdminQueue>.
-+
-+=cut
-+
-+sub CurrentUserCanCreate {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminQueue');
-+}
-+
-+=head2 CurrentUserCanModify
-+
-+Returns true if the current user can modify the queue, using I<AdminQueue>.
-+
-+=cut
-+
-+sub CurrentUserCanModify {
-+ my $self = shift;
-+ return $self->CurrentUserHasRight('AdminQueue');
-+}
-+
- =head2 id
-
- Returns the current value of id.
-diff --git a/lib/RT/Queues.pm b/lib/RT/Queues.pm
-index 5a916d70a0..0d031b8ebe 100644
---- lib/RT/Queues.pm
-+++ lib/RT/Queues.pm
-@@ -128,6 +128,11 @@ sub ItemsOrderBy {
- return $items;
- }
-
-+sub CurrentUserCanSeeAll {
-+ my $self = shift;
-+ return $self->CurrentUser->HasRight( Right => 'SeeQueue', Object => RT->System ) ? 1 : 0;
-+}
-+
- RT::Base->_ImportOverlays();
-
- 1;
-diff --git a/lib/RT/REST2/Resource/Article.pm b/lib/RT/REST2/Resource/Article.pm
-index f3a0eb32d7..d52fff739d 100644
---- lib/RT/REST2/Resource/Article.pm
-+++ lib/RT/REST2/Resource/Article.pm
-@@ -80,17 +80,11 @@ sub create_record {
-
- return (\400, "Invalid Class") if !$data->{Class};
-
-- my $class = RT::Class->new(RT->SystemUser);
-+ my $class = RT::Class->new($self->current_user);
- $class->Load($data->{Class});
-
-- return (\400, "Invalid Class") if !$class->Id;
--
- return ( \403, $self->record->loc("Permission Denied") )
-- unless $self->record->CurrentUser->HasRight(
-- Right => 'CreateArticle',
-- Object => $class,
-- )
-- and $class->Disabled != 1;
-+ unless $class->Id and !$class->__Value('Disabled') and $class->CurrentUserHasRight('CreateArticle');
-
- my ($ok, $txn, $msg) = $self->_create_record($data);
- return ($ok, $msg);
-diff --git a/lib/RT/REST2/Resource/Asset.pm b/lib/RT/REST2/Resource/Asset.pm
-index a29f637b7c..70e66464ba 100644
---- lib/RT/REST2/Resource/Asset.pm
-+++ lib/RT/REST2/Resource/Asset.pm
-@@ -83,10 +83,8 @@ sub create_record {
- my $catalog = RT::Catalog->new($self->record->CurrentUser);
- $catalog->Load($data->{Catalog});
-
-- return (\400, "Invalid Catalog") if !$catalog->Id;
--
-- return (\403, $self->record->loc("Permission Denied", $catalog->Name))
-- unless $catalog->CurrentUserHasRight('CreateAsset');
-+ return (\403, $self->record->loc("Permission Denied"))
-+ unless $catalog->Id and !$catalog->__Value('Disabled') and $catalog->CurrentUserHasRight('CreateAsset');
-
- return $self->_create_record($data);
- }
-diff --git a/lib/RT/REST2/Resource/Collection.pm b/lib/RT/REST2/Resource/Collection.pm
-index 2f0f16eab2..7653d5695c 100644
---- lib/RT/REST2/Resource/Collection.pm
-+++ lib/RT/REST2/Resource/Collection.pm
-@@ -189,7 +189,7 @@ sub serialize {
-
- my %results = (
- count => scalar(@results) + 0,
-- total => $collection->CountAll + 0,
-+ total => $collection->CurrentUserCanSeeAll ? ( $collection->CountAll + 0 ) : undef,
- per_page => $collection->RowsPerPage + 0,
- page => ($collection->FirstRow / $collection->RowsPerPage) + 1,
- items => \@results,
-@@ -205,18 +205,20 @@ sub serialize {
- }
- }
-
-- $results{pages} = ceil($results{total} / $results{per_page});
-- if ($results{page} < $results{pages}) {
-- my $page = $results{page} + 1;
-- $uri->query_form( @query_form, page => $results{page} + 1 );
-- $results{next_page} = $uri->as_string;
-- };
-- if ($results{page} > 1) {
-- # If we're beyond the last page, set prev_page as the last page
-- # available, otherwise, the previous page.
-- $uri->query_form( @query_form, page => ($results{page} > $results{pages} ? $results{pages} : $results{page} - 1) );
-- $results{prev_page} = $uri->as_string;
-- };
-+ $results{pages} = defined $results{total} ? ceil($results{total} / $results{per_page}) : undef;
-+ if ( $results{pages} ) {
-+ if ($results{page} < $results{pages}) {
-+ my $page = $results{page} + 1;
-+ $uri->query_form( @query_form, page => $results{page} + 1 );
-+ $results{next_page} = $uri->as_string;
-+ }
-+ if ($results{page} > 1) {
-+ # If we're beyond the last page, set prev_page as the last page
-+ # available, otherwise, the previous page.
-+ $uri->query_form( @query_form, page => ($results{page} > $results{pages} ? $results{pages} : $results{page} - 1) );
-+ $results{prev_page} = $uri->as_string;
-+ }
-+ }
-
- return \%results;
- }
-diff --git a/lib/RT/REST2/Resource/CustomField.pm b/lib/RT/REST2/Resource/CustomField.pm
-index 62e2d737b7..1924a95f2f 100644
---- lib/RT/REST2/Resource/CustomField.pm
-+++ lib/RT/REST2/Resource/CustomField.pm
-@@ -87,21 +87,6 @@ sub serialize {
- return $data;
- }
-
--sub forbidden {
-- my $self = shift;
-- my $method = $self->request->method;
-- if ($self->record->id) {
-- if ($method eq 'GET') {
-- return !$self->record->CurrentUserHasRight('SeeCustomField');
-- } else {
-- return !($self->record->CurrentUserHasRight('SeeCustomField') && $self->record->CurrentUserHasRight('AdminCustomField'));
-- }
-- } else {
-- return !$self->current_user->HasRight(Right => "AdminCustomField", Object => RT->System);
-- }
-- return 0;
--}
--
- sub hypermedia_links {
- my $self = shift;
- my $links = $self->_default_hypermedia_links(@_);
-diff --git a/lib/RT/REST2/Resource/Group.pm b/lib/RT/REST2/Resource/Group.pm
-index 58f46c1255..c955d1558f 100644
---- lib/RT/REST2/Resource/Group.pm
-+++ lib/RT/REST2/Resource/Group.pm
-@@ -58,9 +58,7 @@ extends 'RT::REST2::Resource::Record';
- with 'RT::REST2::Resource::Record::Readable'
- => { -alias => { serialize => '_default_serialize' } },
- 'RT::REST2::Resource::Record::DeletableByDisabling',
-- => { -alias => { delete_resource => '_delete_resource' } },
- 'RT::REST2::Resource::Record::Writable',
-- => { -alias => { create_record => '_create_record' } },
- 'RT::REST2::Resource::Record::Hypermedia'
- => { -alias => { hypermedia_links => '_default_hypermedia_links' } };
-
-@@ -102,33 +100,20 @@ sub hypermedia_links {
- return $links;
- }
-
--sub create_record {
-+override forbidden => sub {
- my $self = shift;
-- my $data = shift;
-
-- return (\403, $self->record->loc("Permission Denied"))
-- unless $self->current_user->HasRight(
-- Right => "AdminGroup",
-- Object => RT->System,
-- );
--
-- return $self->_create_record($data);
--}
--
--sub delete_resource {
-- my $self = shift;
--
-- return (\403, $self->record->loc("Permission Denied"))
-- unless $self->record->CurrentUserHasRight('AdminGroup');
--
-- return $self->_delete_resource;
--}
--
--sub forbidden {
-- my $self = shift;
-- return 0 unless $self->record->id;
-- return !$self->record->CurrentUserHasRight('SeeGroup');
--}
-+ # For historical reasons, RT::Group::CurrentUserCanSee always returns true.
-+ # For REST2, we want to check SeeGroup.
-+ no warnings 'redefine';
-+ my $original_can_see = \&RT::Group::CurrentUserCanSee;
-+ local *RT::Group::CurrentUserCanSee = sub {
-+ my $self = shift;
-+ return 0 unless $original_can_see->($self, @_);
-+ return $self->CurrentUserHasRight('SeeGroup');
-+ };
-+ return super();
-+};
-
- __PACKAGE__->meta->make_immutable;
-
-diff --git a/lib/RT/REST2/Resource/GroupMembers.pm b/lib/RT/REST2/Resource/GroupMembers.pm
-index 4c0bb0a49a..df555babec 100644
---- lib/RT/REST2/Resource/GroupMembers.pm
-+++ lib/RT/REST2/Resource/GroupMembers.pm
-@@ -114,9 +114,7 @@ sub dispatch_rules {
-
- sub forbidden {
- my $self = shift;
-- return 0 unless $self->group->id;
- return !$self->group->CurrentUserHasRight('AdminGroupMembership');
-- return 1;
- }
-
- sub serialize {
-diff --git a/lib/RT/REST2/Resource/ObjectCustomFieldValue.pm b/lib/RT/REST2/Resource/ObjectCustomFieldValue.pm
-index b9d6fa1cb3..4dbc9cb7a8 100644
---- lib/RT/REST2/Resource/ObjectCustomFieldValue.pm
-+++ lib/RT/REST2/Resource/ObjectCustomFieldValue.pm
-@@ -71,12 +71,6 @@ sub content_types_provided {
- { [ {$self->record->ContentType || 'text/plain; charset=utf-8' => 'to_binary'} ] };
- }
-
--sub forbidden {
-- my $self = shift;
-- return 0 unless $self->record->id;
-- return !$self->record->CurrentUserHasRight('SeeCustomField');
--}
--
- sub to_binary {
- my $self = shift;
- unless ($self->record->CustomFieldObj->Type =~ /^(?:Image|Binary)$/) {
-diff --git a/lib/RT/REST2/Resource/RT.pm b/lib/RT/REST2/Resource/RT.pm
-index 6a31ba3a71..724880af72 100644
---- lib/RT/REST2/Resource/RT.pm
-+++ lib/RT/REST2/Resource/RT.pm
-@@ -71,7 +71,9 @@ sub to_json {
- my $self = shift;
- return JSON::to_json({
- Version => $RT::VERSION,
-- Plugins => [ RT->Config->Get('Plugins') ],
-+ $self->current_user->HasRight( Object => RT->System, Right => 'SuperUser' )
-+ ? ( Plugins => [ RT->Config->Get('Plugins') ] )
-+ : (),
- }, { pretty => 1 });
- }
- __PACKAGE__->meta->make_immutable;
-diff --git a/lib/RT/REST2/Resource/Record.pm b/lib/RT/REST2/Resource/Record.pm
-index b335dab09e..df1223e993 100644
---- lib/RT/REST2/Resource/Record.pm
-+++ lib/RT/REST2/Resource/Record.pm
-@@ -100,10 +100,21 @@ sub resource_exists {
-
- sub forbidden {
- my $self = shift;
-- return 0 unless $self->record->id;
-+ my $method = $self->request->method;
-+
-+ my $right_method;
-+ if ( $self->record->id ) {
-+ $right_method = $method =~ /^(?:GET|HEAD)$/ ? 'CurrentUserCanSee' : 'CurrentUserCanModify';
-+ }
-+ else {
-+ # Even without id, the method can be GET, e.g. to access a not-exsting record.
-+ $right_method = $method =~ /^(?:GET|HEAD)$/ ? 'CurrentUserCanSee' : 'CurrentUserCanCreate';
-+ }
-+
-+ if ( $self->record->can($right_method) ) {
-+ return !$self->record->$right_method;
-+ }
-
-- my $can_see = $self->record->can("CurrentUserCanSee");
-- return 1 if $can_see and not $self->record->$can_see();
- return 0;
- }
-
-diff --git a/lib/RT/REST2/Resource/Ticket.pm b/lib/RT/REST2/Resource/Ticket.pm
-index 1873f0a636..64b4d67647 100644
---- lib/RT/REST2/Resource/Ticket.pm
-+++ lib/RT/REST2/Resource/Ticket.pm
-@@ -225,16 +225,11 @@ sub validate_input {
- if ( $args{'Action'} eq 'create' ) {
- return (0, "Could not create ticket. Queue not set", 400) if !$data->{Queue};
-
-- my $queue = RT::Queue->new(RT->SystemUser);
-+ my $queue = RT::Queue->new($self->current_user);
- $queue->Load($data->{Queue});
-
-- return (0, "Unable to find queue", 400) if !$queue->Id;
--
-- return (0, $self->record->loc("No permission to create tickets in the queue '[_1]'", $queue->Name), 403)
-- unless $self->record->CurrentUser->HasRight(
-- Right => 'CreateTicket',
-- Object => $queue,
-- ) and $queue->Disabled != 1;
-+ return (0, $self->record->loc("No permission to create tickets in the queue '[_1]'", $data->{Queue}), 403)
-+ unless $queue->Id and $queue->__Value('Disabled') != 1 and $queue->CurrentUserHasRight('CreateTicket');
- }
-
- if ( $args{'Action'} eq 'update' ) {
-diff --git a/lib/RT/REST2/Resource/User.pm b/lib/RT/REST2/Resource/User.pm
-index 510a8c7740..af4c8c0c2b 100644
---- lib/RT/REST2/Resource/User.pm
-+++ lib/RT/REST2/Resource/User.pm
-@@ -105,9 +105,8 @@ around 'serialize' => sub {
-
- sub forbidden {
- my $self = shift;
-- return 0 if not $self->record->id;
-- return 0 if $self->record->id == $self->current_user->id;
- return 0 if $self->current_user->Privileged;
-+ return 0 if ( $self->record->id || 0 ) == $self->current_user->id;
- return 1;
- }
-
-diff --git a/lib/RT/SearchBuilder.pm b/lib/RT/SearchBuilder.pm
-index adb1e4e953..03088d9394 100644
---- lib/RT/SearchBuilder.pm
-+++ lib/RT/SearchBuilder.pm
-@@ -1150,6 +1150,11 @@ sub DistinctFieldValues {
- return @values;
- }
-
-+sub CurrentUserCanSeeAll {
-+ my $self = shift;
-+ return $self->CurrentUser->HasRight( Right => 'SuperUser', Object => RT->System ) ? 1 : 0;
-+}
-+
- RT::Base->_ImportOverlays();
-
- 1;
-diff --git a/lib/RT/SearchBuilder/Role/Roles.pm b/lib/RT/SearchBuilder/Role/Roles.pm
-index ac36e8538c..06462d3e88 100644
---- lib/RT/SearchBuilder/Role/Roles.pm
-+++ lib/RT/SearchBuilder/Role/Roles.pm
-@@ -97,7 +97,7 @@ sub _RoleGroupClass {
-
- sub _RoleGroupsJoin {
- my $self = shift;
-- my %args = (New => 0, Class => '', Name => '', @_);
-+ my %args = (New => 0, Class => '', Name => '', Alias => 'main', @_);
-
- $args{'Class'} ||= $self->_RoleGroupClass;
-
-@@ -118,7 +118,7 @@ sub _RoleGroupsJoin {
- # Previously (before 4.4) this used an inner join.
- my $groups = $self->Join(
- TYPE => 'left',
-- ALIAS1 => 'main',
-+ ALIAS1 => $args{Alias},
- FIELD1 => $instance,
- TABLE2 => 'Groups',
- FIELD2 => 'Instance',
-diff --git a/lib/RT/Ticket.pm b/lib/RT/Ticket.pm
-index 741d2e3007..ec7f6922fb 100644
---- lib/RT/Ticket.pm
-+++ lib/RT/Ticket.pm
-@@ -3788,6 +3788,10 @@ sub Serialize {
- $obj->Load( $store{EffectiveId} );
- $store{EffectiveId} = \($obj->UID);
-
-+ unless ( $self->CurrentUserCanSeeTime ) {
-+ delete $store{$_} for qw/TimeEstimated TimeLeft TimeWorked/;
-+ }
-+
- return %store;
- }
-
-diff --git a/lib/RT/Tickets.pm b/lib/RT/Tickets.pm
-index fbaa2d602a..99fd3db13f 100644
---- lib/RT/Tickets.pm
-+++ lib/RT/Tickets.pm
-@@ -2856,7 +2856,8 @@ sub CurrentUserCanSee {
- return unless @queues;
- $self->Limit(
- SUBCLAUSE => 'ACL',
-- ALIAS => 'main',
-+ # RT::Transactions::CurrentUserCanSee reuses RT::Tickets::CurrentUserCanSee
-+ ALIAS => $self->isa('RT::Transactions') ? $self->_JoinTickets : 'main',
- FIELD => 'Queue',
- OPERATOR => 'IN',
- VALUE => [ @queues ],
-@@ -2912,6 +2913,8 @@ sub CurrentUserCanSee {
- FIELD => 'Owner',
- VALUE => $id,
- ENTRYAGGREGATOR => $ea,
-+ # RT::Transactions::CurrentUserCanSee reuses RT::Tickets::CurrentUserCanSee
-+ ALIAS => $self->isa('RT::Transactions') ? $self->_JoinTickets : 'main',
- );
- }
- else {
-@@ -3563,6 +3566,12 @@ sub Query {
- return $self->{_sql_query};
- }
-
-+sub CurrentUserCanSeeAll {
-+ my $self = shift;
-+ return 1 if RT->Config->Get('UseSQLForACLChecks');
-+ return $self->CurrentUser->HasRight( Right => 'ShowTicket', Object => RT->System ) ? 1 : 0;
-+}
-+
- RT::Base->_ImportOverlays();
-
- 1;
-diff --git a/lib/RT/Transactions.pm b/lib/RT/Transactions.pm
-index 21ca3cd86e..e03d2995a8 100644
---- lib/RT/Transactions.pm
-+++ lib/RT/Transactions.pm
-@@ -142,7 +142,28 @@ sub AddRecord {
- my $self = shift;
- my ($record) = @_;
-
-- return unless $record->CurrentUserCanSee;
-+ if ( $self->{_is_ticket_only_search} && RT->Config->Get('UseSQLForACLChecks') ) {
-+ # UseSQLForACLChecks implies ShowTicket only, need to check out extra rights here.
-+ my $type = $record->__Value('Type');
-+ if ( $type eq 'Comment' ) {
-+ return unless $record->CurrentUserHasRight('ShowTicketComments');
-+ }
-+ elsif ( $type eq 'CommentEmailRecord' ) {
-+ return
-+ unless $record->CurrentUserHasRight('ShowTicketComments')
-+ && $record->CurrentUserHasRight('ShowOutgoingEmail');
-+ }
-+ elsif ( $type eq 'EmailRecord' ) {
-+ return unless $record->CurrentUserHasRight('ShowOutgoingEmail');
-+ }
-+ elsif ( $type eq 'CustomField' ) {
-+ return unless $record->CurrentUserCanSee;
-+ }
-+ }
-+ else {
-+ return unless $record->CurrentUserCanSee;
-+ }
-+
- return $self->SUPER::AddRecord($record);
*** 280 LINES SKIPPED ***