Currently the update script only allows the first user to run the update script. A lot of drupal sites have more than one administrator. I think it's best to change the permission check from

if (($access_check == FALSE) || ($user->uid == 1)) {

to something like

if (($access_check == FALSE) || user_access('update')) {

CommentFileSizeAuthor
#96 67234-update-permission-D7.patch15.73 KBDave Reid
#93 67234-update-permission-D7.patch15.75 KBDave Reid
#89 67234-update-permission-D7.patch30.22 KBDave Reid
#87 67234-update-permission-D7.patch25.95 KBDave Reid
#86 67234-update-permission-D7.patch24.83 KBDave Reid
#81 drupal.update-access-RTBC.patch15.71 KBsun
#80 67234-update-permission-D7.patch12.02 KBDave Reid
#79 drupal.update-access-getabsoluteurl.patch14.03 KBsun
#74 67234-update-permission-D7.patch13.75 KBDave Reid
#68 67234-update-permission-D7.patch11.15 KBDave Reid
#62 67234-update-permission-D7.patch11.2 KBDave Reid
#60 67234-update-permission-D7.patch11.05 KBDave Reid
#58 67234-update-permission-D7.patch11.04 KBDave Reid
#56 67234-update-permission-D7.patch11.04 KBDave Reid
#50 67234_administer_site_updates_50.patch8 KBDavid_Rothstein
#47 67234_administer_site_updates_47.patch6.41 KBDavid_Rothstein
#46 67234_administer_site_updates_46.patch7.08 KBDavid_Rothstein
#41 67234_administer_site_updates.patch5.27 KBmikejoconnor
#39 67234-39.update_permission.d7.patch5.26 KBdww
#35 67234.patch5.16 KBRobLoach
#31 67234-31.update_permission.d7.patch4.19 KBdww
#30 67234-30.update_permission.d7.patch4.2 KBdww
#25 67234-update-permission-D7.patch8.88 KBDave Reid
#16 67234-update-permission-D7.patch9.85 KBDave Reid
#14 67234-update-permission-D7.patch9.84 KBDave Reid
#13 67234-update-permission-D7.patch9.84 KBDave Reid
#7 update-script-access-rights_3.patch1.63 KBrstamm
#5 update-script-access-rights_2.patch596 bytesrstamm
#3 update-script-access-rights.patch571 bytesrstamm
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

chx’s picture

Version: 4.7.2 » x.y.z
Category: bug » feature

-1 though, I do not like the idea. Others might.

rstamm’s picture

make sense

but it should be user_access('administer site configuration')

because users who have permission to enable and disable modules should be authorized to run the update script too.

rstamm’s picture

Status: Active » Needs review
FileSize
571 bytes
lennart’s picture

I think this change would be logical and user friendly. Why not allow uid = 1 to give this permission to others?

rstamm’s picture

patch re-rolled.

moshe weitzman’s picture

updating the site is irreversible and serious. i don't think 'administer site configuration' is enough ... personally, i would like to see a built in superuser role which behaves just like uid=1. this idea was dismissed years ago but we can still try again :)

rstamm’s picture

Added new permission 'administer modules configuration' to patch.

Only users with this permission can enable modules and run the update script.

lennart’s picture

in my opinion this change is warrented is some way or the other. Simply because it has to be down very often because many modules now also use the updat system. It is *not* like before when an update was only done when a new version of core appeared. Also you need ftp access to really change anything, without file changes running update will have no consequences.

webchick’s picture

Version: x.y.z » 6.x-dev
Status: Needs review » Needs work

patching file update.php
Hunk #1 succeeded at 768 with fuzz 1 (offset 71 lines).
(Stripping trailing CRs from patch.)
patching file modules/system/system.module
Hunk #1 FAILED at 52.
Hunk #2 FAILED at 187.

I'm also not sure of this. Given that update.php touches the database (and sometimes in destructive ways), it is quite reasonable to demand that the person who runs update.php have enough permissions to ssh into the server and change $access_check to FALSE if they don't have the uid 1 credentials. Plus, if the database is totally fubar (as it can be during a major version update) I'm not sure the user_access() check would necessarily always work anyway.

catch’s picture

Version: 6.x-dev » 7.x-dev

bumping. access check was moved to settings.php right? maybe this should be won't fix with that change.

Dave Reid’s picture

Just marked #382874: Add permission to run update.php as a duplicate and would like to re-roll for 7.x.

Dave Reid’s picture

Adding tags.

Dave Reid’s picture

Status: Needs work » Needs review
FileSize
9.84 KB

Re-rolled patch from #382874: Add permission to run update.php, and adding a few thing I thought were useful.

1. Sends a 403 denied PHP header and logs the access denied in watchdog if a user is denied access to update.php.
2. Wrote TESTS! YAY!
3. Added a simple update_l() function so it's easier to write links in update.php, and also gets rid of writing un-clean urls (http://mysite.com/?q=admin) when it should just be linking to http://mysite.com/admin.

Dave Reid’s picture

Teeny tiny revision renaming the test class from UpdateFunctionalTest to UpdateScriptFunctionalTest.

Should be ready for review!

Dave Reid’s picture

Assigned: Unassigned » Dave Reid
Issue tags: -Needs tests
Dave Reid’s picture

Fudging the order of update_access_denied_page() just a bit. Last revision before bed I promise.

Status: Needs review » Needs work

The last submitted patch failed testing.

RobLoach’s picture

Sasha Chua brought up an issue related to this recently in her blog: Drupal Gotcha: Watch out for $user during update.php. It isn't really related to update.php, but Drupal's dependency on $user->uid == 1.

All the Drupal websites I create, I always end up hacking Drupal's update.php and replace this check with a user_access('administer site configuration')-like statement, so I'd love to see this go in. I like where the patch at #16 is going.

RobLoach’s picture

Status: Needs work » Needs review

Resubmitting to the testing bot, I'm getting passes.

Status: Needs review » Needs work

The last submitted patch failed testing.

sachac’s picture

Oh! That's more about if you set the access check to false, you might not have $user->uid 1... =)

Dave Reid’s picture

Status: Needs work » Needs review

Wow I cannot duplicate these testbot results. :/

Status: Needs review » Needs work

The last submitted patch failed testing.

Dave Reid’s picture

Status: Needs work » Needs review
FileSize
8.88 KB

Testing a simplified test version.

Status: Needs review » Needs work

The last submitted patch failed testing.

Dave Reid’s picture

Yep. That confirms it. I apparently can't test users accessing update.php.

catch’s picture

Yeah update.php is untestable currently. But that means we can get this in with no tests as long as someone runs it manually quickly.

dww’s picture

In an attempt to get some of the hacks we run on d.o into drupal core, long ago I submitted #104868: allow array of update.php super users. That ended up being won't fixed in favor of this issue, in the hopes this would make it into D5... 2 major release later... ;)

Of course we need this patch -- this is one of the most frequently hacked lines of core. We do it on d.o. For (hopefully) obvious reasons, we never want to just disable the access check on d.o/update.php by editing the file via the shell, but it's probably been 2+ years since uid 1 ran any DB updates on this site. So, we've got an array of uids that are also allowed. As the comments here suggest, lots people hack this line of core for the obvious reason that the functionality core provides out of the box is far too limited to be useful in many cases.

If "don't hack core" is supposed to be such an important slogan/mantra for our project, then we have to get rid of stupid code that everyone has to hack to get their work done...

So, looking at the patch:

A) "Added a simple update_l() function..." That's a totally separate feature request. Makes this patch harder to review, and less likely to get in. Can we move that to a separate issue and simplify this patch? #include "kittens.h";

B) "Administer site updates" probably shouldn't be wrapped in code tags in the update_access_denied_page() text, should it? Don't we usually use em for things like that in other parts of core? Also, semantically, it's not code...

C) Seems like we should remove the tests from this patch.

This patch really only needs to be about 10 lines long. That'd help get it in quicker.

Thanks,
-Derek

dww’s picture

Status: Needs work » Needs review
FileSize
4.2 KB
dww’s picture

Whoops, forgot 29.B.

sun’s picture

subscribing - thanks, catch! :)

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

Looks great to me.

sun’s picture

Status: Reviewed & tested by the community » Needs work
+    'administer site updates' => array(
+      'title' => t('Administer site updates'),
+      'description' => t('Run the update.php script.'),
+    ),

Hm. There is not much to "administer" with this permission. I would rather opt for:

+    'access site updates' => array(
+      'title' => t('Execute site updates'),
+      'description' => t('Run the update.php script.'),
+    ),

...or similar.

- * If you are not logged in as administrator, you will need to modify the access
- * check statement inside your settings.php file. After finishing the upgrade,
- * be sure to open settings.php again, and change it back to its original state!
+ * If you are not logged in as administrator or do not have the
+ * 'administer site updates' permission, you will need to modify the
+ * access check statement inside your settings.php file. After
+ * finishing the upgrade, be sure to open settings.php again, and
+ * change it back to its original state!

Wraps at 70 instead of 80 chars.

-  return '<p>Access denied. You are not authorized to access this page. Please log in as the admin user (the first user you created). If you cannot log in, 
+  return '<p>Access denied. You are not authorized to access this page. Please give your user the <em>Administer site updates</em> permission, or log in as the admin user (the first user you created). If you cannot log in, 

Please grant your user the..., I think.

RobLoach’s picture

Status: Needs work » Needs review
FileSize
5.16 KB

This patch takes the recommendations from sun as well as updates default.settings.php to include documentation about the new "access site updates" permission.

As a side note, trying not to bikeshed everything, you kind of do "Administer site updates" when you visit update.php, because you choose which database updates you want to perform. Any thoughts?

moshe weitzman’s picture

A while ago, we got rid of the ability to choose which updates to perform.

sun’s picture

Thanks for re-rolling.

+ <li>To avoid having this problem in future, remember to log in to your website as a user with the <em>Administer site updates</em> permission, or as the admin user (the user you first created) before you backup your database at the beginning of the update process.</li>
...
+$update_access_allowed = !empty($update_free_access) || user_access('administer site updates');

Two remaining instances of 'administer site updates'.

Please also note that

+    'access site updates' => array(
+      'title' => t('Execute site updates'),

was a quick proposal only. Actually, I don't know whether we usually keep the internal and human readable names consistent or not. If we do, "Access site updates" might sound a bit strange as permission title, while the internal name probably makes most sense to developers. Bah. Better suggestions welcome.

UX team-compatible output of this permission:

[ ] Access site updates

Run the update.php script.

Let's point someone of them here. (Bojhan/yoroy/...)

sun’s picture

Issue tags: +Needs usability review

.

dww’s picture

I'm still in favor of "Administer site updates". It's possible this permission (c|sh)ould be reused over at #395472: Plugin Manager in Core: Part 1 (backend). It's also more consistent with other core permissions, and self-documents itself as an "admin" thing not to give out lightly. If I was brand new, and wasn't closely reading the help text, and I just saw "execute site updates" I might think that gives people the permission to "update" the site by changing or adding new content, etc.

The previous patch didn't complete the conversion, anyway, and still had a few word-wrap errors...

So, here's a re-roll incorporating the documentation for default.settings.php, leaving everything as "Administer site updates", but otherwise addressing sun's previous concerns and Rob Loach's improvements.

@UX reviewers, the question is which of these do you like on the permission settings page:

A) "Administer site updates" (this patch)

B) "Execute site updates" (patch #35, but needs work)

C) "Access site updates" (proposal from #38, no patch)

D) Something better y'all propose. ;)

catch’s picture

I'd got for A for the reasons dww gives - lets us use it more flexibly later on.

mikejoconnor’s picture

I'm for "Administer site updates". Here's a new patch to correct a stray "access site updates" in the comments, and changes an "administer" to "Administer".

Dries’s picture

I agree that "Administer site updates" is best. But ... how about "Perform Drupal upgrades"?

That is, how about (i) administer vs perform, (ii) updates vs upgrades and (iii) Drupal vs site? :)

A "site update" could potentially be very confusing -- site owners update their site all the time ... in their minds, adding content might be updating their site.

catch’s picture

Status: Needs review » Needs work

Running user_access() inside update.php currently results in a fatal error on 6-7 updates because the {user_roles} table name has changed.

That update probably needs to be moved to update_fix_d7_requirements() anyway in case an enabled module calls user_access() in hook_boot() or something, but makes sense to do it here.

webchick’s picture

I don't think we should do iii (Drupal vs. site) because we generally go way out of our way to not embed the word "Drupal" in anything user-facing to allow for white-label distributions. Esp. permissions which, although they are now translatable in D7, are hard-coded strings in the code.

dww’s picture

I don't mind (ii) "upgrades" not "updates", but I'm opposed to (i) and (iii). As I wrote in comment #39:

I'm still in favor of "Administer site updates". It's possible this permission (c|sh)ould be reused over at #395472: Plugin Manager in Core: Part 1 (backend). It's also more consistent with other core permissions, and self-documents itself as an "admin" thing not to give out lightly. If I was brand new, and wasn't closely reading the help text, and I just saw "execute site updates" I might think that gives people the permission to "update" the site by changing or adding new content, etc.

So, "Administer site upgrades" would be ok, and further differentiate this permission from "updating (content on) your site"... However, if we're going to reuse this in update.module, it's a little weird that update.module uses a permission called "upgrade". /me shrugs...

David_Rothstein’s picture

Status: Needs work » Needs review
FileSize
7.08 KB

This issue seems worth reviving - it really should be fixed.

Here is an updated patch. For the permission name, I went with "administer software updates" -- it's simple, clear, and could easily be extended to the Plugin Manager if necessary.

Notes:

  1. To deal with #43, I wrapped the call to user_access() in a try/catch block. This isn't likely to actually work right now, and D6->D7 upgrades are broken at an earlier stage of the bootstrap anyway (without this patch), both due to #517742: Upgrade failing if blocked_ips doesn't exist. Also note #524710: role_permission required to upgrade from D6 to D7... overall, this is kind of a mess that needs to be cleaned up later anyway, but I think this patch is fine for now.
  2. The lines in the patch that change from using drupal_get_token() to drupal_valid_token() are necessary to support assigning the new permission to anonymous users. That's a rare use case, I suppose, but if it's a real permission, we probably should be supporting it.
David_Rothstein’s picture

OK, never mind what I said about drupal_valid_token(). That is actually a separate bug (#567826: $update_free_access does not always allow access to update.php) and it's not at all clear that the method used above is the right way to fix it.

So, here's a new patch that does not include the token validation changes.

RobLoach’s picture

Status: Needs review » Reviewed & tested by the community

Tested and works.

Status: Reviewed & tested by the community » Needs work

The last submitted patch failed testing.

David_Rothstein’s picture

sebos69’s picture

Hi,

I just stumbled on this topic, and I am very interested in getting this patch working!

Our problem arises from the fact that we use the Webserver authentification module (driven by an LDAP directory) and we cannot create the "admin" account on this LDAP directory, so running updates is impossible...

webchick’s picture

Status: Needs review » Needs work

Huh. I totally thought I'd already committed this patch. Anyway, I'd like to. ;)

Please also make visibility of the update status error messages contingent on this new permission. In other words, marked #332796: Add permissions to the update.module to hide warnings as a duplicate.

Dave Reid’s picture

I can get this rerolled in the next hour.

moshe weitzman’s picture

@Dave Reid? Anyone? Re-roll?

Dave Reid’s picture

Ok, going to stop promising that I can do this within the hour, but on my MUST-DO-LIST for today.

Dave Reid’s picture

Status: Needs work » Needs review
FileSize
11.04 KB

Re-rolled with PASSING TESTS! YAY!

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

Lovely little patch. Please wait for green before commit.

Dave Reid’s picture

Trivial revised patch that fixes two instances of "administer software updates" to "Administer software updates" in the user interface.

Dave Reid’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
11.05 KB

Trying again not using url() to get the path to update.php.

Status: Needs review » Needs work

The last submitted patch failed testing.

Dave Reid’s picture

Status: Needs work » Needs review
FileSize
11.2 KB

Trying to write tests for update.php is apparently a major pain with this test bot. Revised patch that sends me debugging e-mails. DO NOT COMMIT!

Status: Needs review » Needs work

The last submitted patch failed testing.

Dave Reid’s picture

Status: Needs work » Needs review

I could really use the help of a testbot admin to help figure out what is going wrong here. I just spend the last half hour trying to get my own local pifr install so I could maybe debug it, but I am getting way too frustrated at the lack of documentation, discrepancies between versions of SimpleTest, etc.

sun’s picture

+++ modules/system/system.test	7 Oct 2009 03:44:16 -0000
@@ -1290,3 +1290,61 @@ array_space[a b] = Value';
+    $this->drupalGet($update_url);

$this->drupalGet($update_url, array('external' => TRUE));

I'm on crack. Are you, too?

sun’s picture

So what you have to take into consideration:

- Tests run with clean URLs disabled.

- url() builds a URL to 1) a virtual system (Drupal) path, or 2) an external URL.

- update.php is not a system path, so it is an external URL.

- You may think that you could also use the 'absolute' property, but that does not work, because language rewriting, URL aliasing, and other funky stuff happens.

You don't need to install PIFR to replicate this. Just use your install of HEAD, disable clean URLs, and run that test.

sebos69’s picture

Is there any chance to see this patch land in Drupal 6?

Dave Reid’s picture

@sun: Awesome. Revised patch posted that will hopefully pass. It was too late for me to be rolling this patch. Doesn't SimpleTest change the clean_url variables when it runs?

@sebos69: Since this is a feature request, no.

Status: Needs review » Needs work

The last submitted patch failed testing.

Dave Reid’s picture

Ok still had 3 fails and 1 exception. Any other ideas?

Dave Reid’s picture

ARG. Because the update form doesn't set an exclipit action in its form tag, drupalPost() uses getAbsoluteUrl() on 'update.php' which then tries to attempt to POST to 'http://mysql.drupal7dev.local/?q=update.php&op=selection&token=32b071f90...' which of course is a 404. ARG.

webchick’s picture

Could we add in an $absolute = TRUE parameter to drupalPost()?

sun’s picture

Status: Needs work » Needs review

The problem is getAbsoluteUrl(). I'm trying to solve that nightmare... it's the second time that this ugly code doesn't work at all. (the lengthy comments in there are mine)

Dave Reid’s picture

Revised patch with a small change to DWTC->getAbsoluteUrl() that gets the $options for url() from it's caller. Tested and passes locally. Let's give this a shot with the test bot now.

This could have been fixed just by manually adding $base_url to update.php form action to make it a full URL, but that didn't seem right since we'll likely encounter this again later.

sun’s picture

Regardless of that getAbsoluteUrl() problem, your first assertions for 403 in the tests are failing.

Dave Reid’s picture

Test bot passed them all and they pass locally:
Update.php functionality 50 0 0

Status: Needs review » Needs work

The last submitted patch failed testing.

Dave Reid’s picture

Status: Needs work » Needs review

#$^# I give up on this for now.

sun’s picture

Let's see what breaks.

Dave Reid’s picture

Ok until we can get getAbsoluteUrl() working, this should pass.

sun’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
15.71 KB

There you go. :)

Dave Reid’s picture

Holy dear lord, that was way too frustrating and huge thanks to sun for helping figure that out. Everything looks good, it passes locally, and for the first time the fracking test bot likes it.

RTBC'd!

Dave Reid’s picture

So the issue was that the drupalPost() function had to extract the 'action' URL from the form that it is submitting. In this case the action in update.php was 'update.php?stuff'. When that is run through url() it gets converted into http://mysite.com/?q=update.php, which is wrong. So now we have proper external and absolute handling for drupalPost, which is a Good Thing(tm).

dww’s picture

Status: Reviewed & tested by the community » Needs work

Excellent, great work y'all!

However, I hate to do this, but in all the excitement about fighting the test infrastructure, y'all forgot webchick's request in #52 to solve #332796: Add permissions to the update.module to hide warnings while we're at it. ;) Seems like she's saying that the 'Administer software updates' permission should determine access to all of Update status's menu items and to the warning messages that are set via hook_requirements() in admin/* when the site is missing security updates. A very quick skim of this patch shows no such changes. Anyone up for a re-roll? Sorry!

Dave Reid’s picture

I'm on it.

Dave Reid’s picture

Status: Needs work » Needs review
FileSize
24.83 KB

Revised patch that changes all of update.module's menu permissions from 'administer site configuration' to 'administer software updates' as well as the notifications from update_requirements (also moved to update.install to shrink down the update.module file size a little).

Dave Reid’s picture

Forgot to adjust update.test.

David_Rothstein’s picture

Status: Needs review » Needs work
+    return ($user->uid === 1);

Why not simply return $user->uid == 1; here?

+    // Proceed through the update process without any pending updates.
+    $this->drupalPost(NULL, array(), t('Continue'), array('external' => TRUE));
+    $this->assertText(t('No pending updates.'));
+
+    // Click through back to the administration page.
+    $this->clickLink('Administration pages');
+    $this->assertResponse(200);

The function is called testUpdateAccess() but this part is trying to do a bit more, and in a very fragile way. If we're going to try to test that update.php works correctly, I suggest we do that in a separate issue.

The "click back to the administration page" part seems especially out of place and fragile... though it does point out a (very minor) bug with this patch. In order to get the test to pass, you needed to grant the 'access administration pages' permission in addition to 'administer software updates'. So someone who only has the latter permission would get access denied after clicking on this link.

**

Finally, I was about to point out the same thing as @dww did, but honestly, this patch has already expanded from a simple permission to fixing all of SimpleTest :) I would suggest that #332796: Add permissions to the update.module to hide warnings be reopened as a followup to this instead. It's not totally clear to me that someone without the 'administer software updates' permission should never see any kind of warning message at all - it's equally possible that they should see a message with different text (if, for example, they have 'administer site configuration' and thus are still partially responsible for the overall maintenance of the site).

Dave Reid’s picture

Status: Needs work » Needs review
FileSize
30.22 KB

Moved _update_requirement_check() to update.install as well since it is only called by update_requirements().

dww’s picture

Status: Needs review » Needs work

Nicely done!

+    'administer software updates' => array(
+      'title' => t('Administer software updates'),
+      'description' => t('Run the update.php script.'),
+    ),

That description isn't sufficient anymore. ;)

dww’s picture

(BTW, I agree with David_Rothstein in #88 -- it's not clear to me why we're trying to tackle all the update status parts at the same time. Guess that's what webchick wanted, but it sure seems harmful to kittens).

Dave Reid’s picture

Status: Needs work » Needs review

What should be put for the permission description since it adds features when update.module is installed?

The tests for testing the click-through of update.php found bugs in SimpleTest so I think we should just keep those small ones. Tests aren't a bad thing.

Dave Reid’s picture

Re-rolling a simplified patch *just* for permission to update.php. No changes to update.module (split back to #332796: Add permissions to the update.module to hide warnings). This is essentially the same patch as #81 but with only a test for access to update.php, and not the click-through test. There are a few other 403 links on the update results page that I want to fix so I'll create a separate issue for that.

Dave Reid’s picture

Component: update system » update.module

Moving to proper component.

Dave Reid’s picture

Component: update.module » update system

Arg...wrong patch. Sorry everyone.

Dave Reid’s picture

Left in an accidental private $admin_user in the test.

David_Rothstein’s picture

Status: Needs review » Reviewed & tested by the community

The patch looks great now, and I confirmed by hand that it "works" with D6->D7 updates also (which is to say, it doesn't break D6->D7 updates any more than they were already broken).

Now that we have the ability - thanks to the SimpleTest changes - I'll create a followup issue to do a test of running through update.php and checking that it performs/skips updates correctly.

Dave Reid’s picture

David_Rothstein’s picture

I found an existing issue at #383196: update.php tests, so I added a comment there instead.

StevenPatz’s picture

Status: Reviewed & tested by the community » Needs work

Did you remove the debug email lines?
Or does DREditor have a bug?

dww’s picture

@spatz4000: Please don't mark issues "needs work" if you don't even look at the patch. ;) http://drupal.org/files/issues/67234-update-permission-D7_14.patch from comment #96 includes no stray debugging messages. It's still RTBC...

webchick’s picture

Status: Needs work » Fixed

Yeah, when I first came across #332796: Add permissions to the update.module to hide warnings, it seemed a natural extension of this, but there are compelling arguments over there for making it a separate permission.

In the meantime, this looks great, and since I already told all of DC Paris that I committed this patch anyway, committed to HEAD. ;)

Please follow-up with an issue in the Documentation queue about this, since this change will affect several handbook pages.

David_Rothstein’s picture

Status: Fixed » Closed (fixed)
Issue tags: -Needs usability review, -permissions, -update.php

Automatically closed -- issue fixed for 2 weeks with no activity.