Builds out a map for icon->image in Projects, selects the icon's image as the default project image if there is no custom image chosen by the user.
Details
- Reviewers
epriestley - Commits
- rP250aaabd6484: Choose default project image by icon
Select various icons, see image change. Test choose picture, pick a new image.
Diff Detail
- Repository
- rP Phabricator
- Lint
Lint Not Applicable - Unit
Tests Not Applicable
Event Timeline
Project icons are customizable via projects.icons, but this hard-codes support for only the default upstream set.
Instead, you should add a key to the configuration, update the default values and validation in PhabricatorProjectIconSet, and provide a way for users to learn what the acceptable values are (maybe a UIExample?).
This doesn't break anything though, right? It's just a nice benefit to extend it to customization? Or does this path make customization not possible?
This doesn't break anything, but I don't want to take a step backwards here by hard-coding this behavior. If you don't want to fully integrate this change, I can commandeer it and integrate it when I have time.
Specifically, we currently specify the default icons like this, in PhabricatorProjectIconSet:
array( 'key' => 'tag', 'icon' => 'fa-tags', 'name' => pht('Tag'), ),
...and a user might specify an icon in JSON like this:
{ "key": "tag", "icon": "fa-tags", "name": "Tag" }
We should add a key like "image" to the defaults, and allow users to specify an "image" as well. For example, this would let an install rename the "Tag" icon to "Label" with internal key "label" if they think that word is more clear (or "Label, Eh?" if they primarily speak Canadian) , but keep the actual FontAwesome icon () and new illustrated image, since both are appropriate for an icon called "Label".
Ideally, we should let users pick any image and not expose file path internals to the user. For example, if users specify "/v3/" paths and we later replace these with "/v4/", the mapping will break. We don't have a great way to do (or, generally, to formalize builtins and make them extensible) right now so this is likely to require migrations and guidance eventually, but I suppose we can cross that bridge when we come to it.
I think I got everything covered here, other than adding a "uiexamples" page of the built-in images. I can build that out later once I clean up that folder, also having another 8 icons produced currently.
src/applications/project/icon/PhabricatorProjectIconSet.php | ||
---|---|---|
266–268 | This allows attackers to hijack an administrator account, specify paths like ../../config/local/config.json, and then (at least potentially) read credentials and private keys. This code should instead build a list of all the allowed values (you can follow the example in PhabricatorFilesOnDiskBuiltinFile->getAllBuiltinFiles()) and then test if the provided value is on that list. |
src/applications/project/icon/PhabricatorProjectIconSet.php | ||
---|---|---|
266–268 | Can that be done in a static method? |
Yeah, although you'll need a parameter or something if you want to restrict selections to just intended project icons (but maybe you don't).
Some inlines about edge cases.
src/applications/project/controller/PhabricatorProjectEditPictureController.php | ||
---|---|---|
101–105 | (See below for null behavior.) | |
src/applications/project/icon/PhabricatorProjectIconSet.php | ||
278 | I think this error is a little misleading since you actually have to specify "projects/" yourself? (The "." is also inside the quotes, which could be slightly misleading.) That is, if resources/builtin/projects/x.png exists, and I specify "x.png", I'll get this error and be confused since the file definitely exists -- but the code really looked at resources/builtin/x.png, without projects/, even though the error suggests it added projects/ for me. | |
src/applications/project/query/PhabricatorProjectQuery.php | ||
377–381 | This may return null (if configuration does not specify an 'image', and the parameter is optional) and then I think we'll fatal. That is, you should make sure that things work OK if a custom icon does not specify an image. |
I think this might break with these values:
'image' => '' 'image' => '0'
It looks like they'll evade the setup check, but fail to fall back to the default icon.
Doing this purely in a setup check (instead of also when accessing the image) is a tiny bit flimsy: it's possible for configuration values to change without the configuration setup checks running on them. Two examples are: an administrator editing conf/local/local.json, and a dynamic check (like a conf.php file or a SiteSource) making a runtime decision to produce a different value. We don't perform config setup checks every time a value is read, for performance reasons, and we can't detect when a value changes if it's changed outside of our control (editing a file, dynamic source). We could attempt to detect these changes by hashing config, but there'd be some level of performance/correctness tradeoff.
As written, there's currently no way to do anything dangerous with this minor flimsiness, since we always actually load the file through loadBuiltin() now, which does a check that is slightly too loose but would still catch anything dangerous. You can also only change config outside of our control with root access.
We could clean this up in the future, e.g. when UIExamples gets extended or when we run into a use case for third-party builtin files (it would be nice to let extensions add more project icons today if then want, for example, but they can't do it without us making some upstream changes).