Closed (fixed)
Project:
Drupal core
Version:
8.8.x-dev
Component:
file system
Priority:
Normal
Category:
Task
Assigned:
Issue tags:
Reporter:
Created:
21 Nov 2015 at 00:26 UTC
Updated:
14 Oct 2019 at 02:14 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
phenaproximaPretty basic...
Comment #5
phenaproximaRerolled against 8.3.x.
Comment #10
nickolajrework against current core, no interdiff cos lots of changes
Comment #11
andypostLast patch have only part of previous
Comment #12
andypostProper patch, also added missing doc blocks, still needs tests for new service & exception?!
Comment #13
andypostand needs CR
Comment #15
starshaped@phenaproxima and I worked on this. Rather than write new tests, we adapted existing test of file_save_htaccess and added test coverage of the deprecation notices.
Comment #17
chiranjeeb2410 commentedComplete reroll for patch in #2 against latest core. Hope to get a green flag.
Comment #19
andypostWhile working on CR https://www.drupal.org/node/2940126, I found that https://www.drupal.org/node/2418133 does not mentions about conversion of
file_htaccess_lines()probably there was a reason for it... fixedHere's updated patch adds ref to CR & fix most of failures
@chiranjeeb2410 please don't hijack issue patches
Comment #21
andypostFix test failures by replacing usage, added todo and issue #2940135: Use file_system service to \Drupal\Core\Config\FileStorage
Comment #22
andyposta bit of clean-up
Comment #25
robpowellworking on this for SprintWeekend2018
Comment #26
robpowellComment #28
kim.pepperRe-roll of #22
Comment #30
kim.pepperFixes a few tests.
Comment #31
kim.pepperOops! Didn't mean to post my local composer changes!
Comment #32
kim.pepperHere's the correct interdiff between #31 and #28
Comment #34
andypostIt looks that test needs split or only testDeprecatedFunctions() should be marked as @legacy
Comment #35
kim.pepperThanks. Fixes for #34
Comment #36
andypostLet's get commiter's piv, imo good to go
Comment #37
alexpottI think a better service name would be file.htaccess_writer or even core.htaccess_writer as that's the main purpose. Maybe someone else has better suggestions but file.htaccess does not seem that great to me.
HtaccessWriter I think is a better name.
Let's move \Drupal\Component\PhpStorage\FileStorage::htaccessLines() to here and deprecate that. It was only put there to have it in an autoloadable class and this is a better home.
Comment #38
kim.pepperThanks for the review!
Comment #40
kim.pepperHmm. Seems that moving the \Drupal\Component\PhpStorage\FileStorage::htaccessLines to \Drupal\Core\File\HtaccessWriter::htaccessLines is causing a fail because we calling code Drupal\Core from within a Drupal\Component.
Any thoughts on how to resolve that apart from duplicating the code?
Comment #42
alexpott@kim.pepper I think we should continue with calling \Drupal\Component\PhpStorage\FileStorage::htaccessLines() then and file a follow-up to try to resolve this. The other answer is that we should try to make the HtAccessWriter a component but that is going to be nigh on impossible. For me this points to the fact that PhpStorage doesn't really feel like a component either.
Maybe we can find some other similar stuff and make a security component that has this ¯\_(ツ)_/¯
Comment #43
kim.pepperI've reverted the htaccess() move and created follow up #3013210: Add drupal/core-filesecurity component for writing htaccess files.
Comment #45
kim.pepperRemove unused import.
Comment #46
jibran#37 is addressed so back to RTBC.
Comment #47
alexpott", [
+ '%directory' => $directory,
+ '@htaccess' => $htaccess_lines,
+ ]);
+ throw new HtaccessNotWriteableException($directory, $htaccess_lines);
This will result in duplicate errors logged. Why do we want this to throw an exception? If we feel that that is the better architecture then I guess that we could make that change here but it feels an unnecessary change. We need on some level to justify this change.
Comment #48
kim.pepperRe #47 I've removed the exception.
I also added an interface.
Comment #49
jibranInterface additions is good. Back to RTBC as #47 is addressed.
Comment #50
alexpottOne thing I'm asking myself is does this need to be its own service. One thought was to add this to FileSystem but OTOH this is really a HTTP server detail. The next question I asked myself is have we moved all the htaccess logic possible to the new service and I think there's something we're missing. I think it might be worth moving much of the code from
system_requirements()here. So that checking and ensuring is done in the same place. Perhaps there is other htaccess related code dotted about the system that could be moved here.Here's the current code:
We could move this into the new service as something like:
And maybe even refactor the list of directories into a protected method to be shared by the ensure method - so that list is always obtained from the same place.
Comment #51
andypost@alexpott requirements sounds like follow-up and could be merged with #2909480: Move REQUIREMENT_* constants out of install.inc file
Comment #52
alexpott@andypost there thing is we're introducing a new interface so now is a good time to get it right.
Comment #53
kim.pepper#50 sounds like a nice cleanup.
Comment #54
andypostAny reason to use protected var if you always call a method?
Comment #55
kim.pepperAh good point!
I've also re-used the htaccessFiles() method in HtaccessWriter::save() as @alexpott suggested in #50
Comment #56
andypostRemoval of unneeded changes
Comment #57
andypostNaming... maybe better to call it getter...
Comment #58
kim.pepperFixes #57
Also changed variables to camelCase for consistency.
Comment #59
larowlanLooks good, couple of observations
this comment is now outdated
Given we're going to remove this at some stage, should we make it private instead?
nit - phps > 80 chars
Do we want this call to procedural code to be wrapped in a private method so we can extract easily later?
should we remove the 'latest security update' comment now, its not really correct anymore?
nit: this is the only place we capitalize Access. should it just be '.htacess files to scan'?
Comment #60
phenaproximaTook a crack at addressing @larowlan's feedback.
Comment #61
kim.pepperAll feedback in #59 has been addressed so back to rtbc
Comment #62
catchIs there already an issue to move this out of bootstrap.inc?
Rest of the patch looks OK, this looks slightly odd as a service to me, but it's probably because it's only being called by other legacy procedural code atm.
Comment #63
alexpottThere's no issue to deal with the
$config_directoriesglobal. Configuring this in settings.php and having it available as a global feels super unnecessary now. I think this is a legacy of having an active directory and the live config being stored there. I think we could move this to $settings now and use the Settings singleton. I've created #3018015: Move the $config_directories to $settings so it can be accessed via the Settings singletonComment #64
alexpottI was wrong there was an issue to deal with
$config_directories- #2980712: Define config directory in settingsComment #65
alexpottLooking at this now. I'm not sure that the requirements stuff should be here on the interface. In some future world where requirement gathering will be an event maybe this service will listen to that event can construct the appropriate Requirement objects to place text on the requirements page but we're a long way from that. We could consider making getHtaccessFiles() public and using that in system_requirements(). I realise that the existence of checkRequirements on the interface is my fault - cf #50. So here's a patch
Comment #66
kim.pepperI think you're right re the requirements stuff. LGTM.
Comment #68
catchCommitted 56ccba0 and pushed to 8.7.x. Thanks!
Comment #69
berdirSorry for being late to the party, but this introduces some tricky cross-dependency issues.
file_unmanaged_prepare() is being moved into the fileSystem service in #2244513: Move the unmanaged file APIs to the file_system service (file.inc). Which is injected into this new service. That means they will both need each other.
Similar with the config stuff, not sure what the plan is with config_get_config_directory(), but it's a bit strange that this low-level API is calling out to the config system, and then Config\FileStorage uses this API as well. Likely config_get_config_directory() will be even more low-level and possibly just a static function (maybe on Settings?), so possibly that's not a big issue.
Comment #70
catchconfig_get_config_directory() is being dealt with here #2980712: Define config directory in settings.
file_unmanaged_prepare() is a bit trickier to deal with - only thing I can really think of right now is incorporating this into the fileSystem service?
Comment #71
catchComment #72
catchReverted the patch so we can discuss #69 more.
Comment #74
alexpottOne advantage of having this as a separate service is that nginx users (or other webserver users) can swap this out for different implementations. Which I think I think is a good thing. So maybe an event that'll allow us to break the circular dependency is a good idea (as per @Berdir in Slack).
Comment #75
berdirIf we agree that having an event in the file_system service is the best way forward, then I think we can commit this again and then introduce that over there? We can only do it after one of these issues is in anyway.
Comment #76
kim.pepperAgree that an event is a good idea. :-)
Comment #77
catchI don't think we should add events solely to break circular dependencies unless there's no other choice, there's still a circular dependency when we do that, just one that's obscured by a layer of indirection.
However alexpott reminded me about issues like #2619250: Make .htaccess usage work for the widest possible configurations without relaxing security and document pitfalls which provide a use-case for making things alterable here, so that seems a better reason to do it.
Comment #78
kim.pepperSo are we agreed this approach is the preferred one? Or should we postpone on #2244513: Move the unmanaged file APIs to the file_system service (file.inc)
Comment #79
joachim commentedThis doesn't seem to handle the htaccess writing that's done in \Drupal\Component\PhpStorage::ensureDirectory().
Also, because Drupal\Component\PhpStorage::ensureDirectory is in Drupal\Component, that wouldn't be able to use this service, which is in Drupal\Core.
Comment #80
andypost@joachim surely we can't use services in component namespace, that's why it using
file_functions and duplicates code a bit, but nice catch... not sure we can do anything about itComment #81
joachim commented> surely we can't use services in component namespace
Could we put this new htaccess service in the Component namespace, and then Component\PhpStorage can depend on it?
If there are aspects of the htaccess service that need to be in the Core namespace, we can add a 2nd htaccess service there that subclasses / replaces / wraps the Component namespace service.
Comment #82
kim.pepperThat might be an improvement, but I don't think it untangles the circular dependencies.
Comment #83
jibranHere is a reroll of #65.
Comment #84
berdirthis function is now deprecated, so we might want to not even touch it. However, what we do need to touch now is the one inside file_system that replaces this. In #3034072: Move file uri/scheme functions from file.inc and FileSystem to StreamWrapperManager I realized that prepare stuff is even more fun than I thought, because it uses file_build_uri(), which in turn uses \file_default_scheme(), which uses \Drupal::config().
With the final patch for the unmanaged functions, that is now a protected function that is not called from the outside anymore, it's just for copy() and move().
Still thinking how we can make that a service or so, but it seems a bit weird that the crucial validation of source and destination would be in a separate service. One option might be to deprecate the empty-destination thing to get rid of that at least?
And then it's just this htaccess stuff, we could do a setter-injection of this service in file_system?
In that issue, I proposed to use a get/set pattern with optional injection for file_system, we could possibly do the same for this service here? Becaue right now, that other service is already RTBC, but we'll see if it gets in.
Comment #86
andypostComment #88
kostyashupenkoComment #90
joachim commented> That might be an improvement, but I don't think it untangles the circular dependencies.
Where do we get circularity?
I think that we should take a step back here, and pause work on the patch. We should research in the code all the places that need to write htaccess files, and then figure out the dependency hierarchy.
Comment #91
kim.pepperRe-roll of #88 adding the setter injection of htaccessWriter into FileSystem service as per @Berdir's suggestion in #84.
Re: #90 @joachim the circular dependency is: FileSystem -> HtaccessWriter -> FileSystem, hence the setter injection here.
Comment #93
kim.pepperLooks like symfony is detecting a circular reference even with setter injection. Trying a lazy-loading approach instead.
Comment #94
berdir8.8 now
single quotes?
this issue was closed with the final approach being exactly this, so we can remove the todo, maybe comment why we do it like this.
Not sure what to do with this.
I'm not sure why these two lines even exist. They have been like this since 2009, as part of the stream wrapper API introduction. (still inlined into copy back then)
But it's just about ensuring the .htaccess files in the root-level public://, private:// and so on exist, why does a copy/move need to ensure that?
Do we have any tests that fail if we remove it?
some more double quotes.
HtaccessWriter maybe, for variable and inline reference?
Comment #95
kim.pepperComment #96
kim.pepperOops forgot to add patches.
Comment #97
kim.pepperHere's a patch for #94.4 removing the call to $this->getHtaccessWriter()->ensure() inside prepareDestination()
Comment #98
berdirThe big question is whether this is OK. I asked @alexpott and @dww about this, but they weren't sure either. I *think* it is, because they only care about the top-level directory and prepareDestination() will at most once in a lifetime of a drupal site attempt to actually create sites/default/files (not sure it tries to do that at all), so why does it need to check that every. single. time we copy/move a file around? Makes no sense to me :)
Comment #99
kim.pepperSo where do we go from here? I'm tagging Needs framework manager review to get some input from the framework managers themselves.
Comment #100
berdirI guess that makes sense, and also back to RTBC, as I said, IMHO this removal makes sense :)
Comment #101
johnwebdev commentedThis is a pretty good example where OOP shines. We're now able to swap this implementation for another that nullifies the behaviour, i.e. if you use nginx as a web server, there is no need for .htaccess files to be created.
Sweet :)
Comment #102
kim.pepperComment #103
kim.pepperReroll after #3021434: Properly deprecate drupal_unlink()
Comment #104
kim.pepperJust a re-roll so back to RTBC
Comment #105
kim.pepperRe-roll of #103
Comment #106
kim.pepperUpdated to use latest deprecation message format.
Comment #107
andypostComment #108
kim.pepperRe-roll of #106. Also updated deprecation message format to comply with coding standards.
Comment #110
kim.pepperRemoves usages of deprecated FileSystem::uriScheme() and file_stream_wrapper_uri_normalize()
Comment #111
kim.pepperComment #112
kim.pepperRe-roll after #2980712: Define config directory in settings
Comment #114
kim.pepperFail due to #3059332: Mark kernel tests that perform no assertions as risky
Comment #116
kim.pepperGah, not sure why file_save_htaccess($public) is false in the deprecation test?
Comment #117
berdirI'm wondering if the call in FileStorage is even still necessary. We are explicitly checking the staging idrectory in the ensure() method and support for other config directories is deprecated per https://www.drupal.org/node/3018145.
But maybe we can leave it like this and think about that in a follow-up? Now that it's a private method, we can always remove it later.
I pointed out before why I think it is OK to remove this call, see #98
Because the parent directory doesn't exist apparently, adding this line above makes it work:
\Drupal::service('file_system')->prepareDirectory($public, FileSystemInterface::CREATE_DIRECTORY);
Lets add that to make it a bit more realistic, then I'll set it back to RTBC.
Comment #118
kim.pepperComment #119
berdir2. Yup, this was meant as a pointer for said framework maintainer :)
Back to RTBC.
Comment #120
kim.pepperRe-roll of #118
Comment #121
mile23Updated follow-up: #3013210-3: Add drupal/core-filesecurity component for writing htaccess files
Comment #122
larowlanso we didn't opt for the event? I can't see any discussion of why the event idea was dropped after comment #77
I'm also not sure we can do this.
Yes, we setup this file on install, but in some cases we copy databases around or migrate sites from one host to another, I think in those cases, we should be still ensuring this file exists.
", [
+ '%directory' => $directory,
+ '@htaccess' => $htaccessLines,
+ ]);
we don't need this else, we return above.
hmm, although we do end up creating them again here... which will alert the admin if update.module is enabled - see
update_page_topWhat if we put a call somewhere like drupal_flush_all_caches as well, then perhaps we could do away with it in prepareDirectory
wow this function 🤔 only used by locale module but defined in system.module and in RAM on every drupal page request.
Worth a follow up to deprecate it/move it to an include/move it to locale.module?
Comment #123
kim.pepperWhat would that look like? Would we just have an 'DirectoryCreated' event and have the HtAccessWriter a subscriber? If users are using nginx + php-fpm could just remove the subscriber?
Comment #124
kim.pepperPatch for #123.3
Comment #125
larowlanI'm saying that the ::ensure call also happens when hook_requirements fires.
Which seems to occur from
\Drupal\system\Controller\SystemController::overviewwhich means any admin overview page would also trigger this, so maybe we don't need it for prepareDirectory.Comment #126
kim.pepperComment #127
kim.pepperConfirmed with @larowlan in slack that he meant prepareDestination() in #125, so I think that addresses #122.2 & .4
Just need some consensus on the event design decision?
Comment #128
kim.pepperHad a go at using an event in config/FileStorage.php and it introduced a lot of changes.
Putting it up here to see what blows up.
Comment #129
andypostaffecting this constructors always reminds me about related #2657548: [PP-1] Add a factory method to create FileStorage instances
Comment #131
kim.pepperFixing some test fails.
Comment #133
kim.pepperHaving trouble tracking down FileStorage::__construct() with a NULL $event_dispatcher. 🤔
Comment #134
mile23So here's the test fail for
DefaultConfigTest:Here's
DefaultConfigTest::testDefaultConfig():What's a
TestInstallStorage? It's a subclass ofInstallStoragewhich is a subclass ofFileStorage.So there's one. :-)
Same deal for
TestViewsTest.There's also
ExtensionInstallStoragewhich suffers the same fate in a few different tests, like for instanceExtensionInstallStorageTest.Comment #135
berdirOuch. Maybe we can explore the event subscriber idea in a follow-up? Adding 40kb to this patch to avoid a single \Drupal::service() is pretty wild. We've struggled with dependencies of FileStorage before in #2940135: Use file_system service to \Drupal\Core\Config\FileStorage And while that was even worse due to cross-dependency, part of the decision was that we'd need so many changes.
Comment #136
kim.pepperYep sure. I guess that's a question for the framework managers?
Comment #137
andypostI'd say it's best time to summon cmi2 initiative here - config storage is pita to extend but it often required, meantime they manage https://www.drupal.org/node/2943918
It looks more like "super class" which needs split, file system also becomes more "smart" so probably htaccess writer could live at composer level...
Comment #138
larowlanyeah, sorry about the side-track, but we're kind of playing whack-a-mole here, one singleton call swapped for another. I'll discuss with another framework manager, but I'm leaning towards this not being worth it, unless we have a solid use-case for someone else implementing an event listener.
Comment #139
kim.pepperOK cool. I think to untangle the mess we first need to fix:
This should help manage FileStorage changes going forward allowing us to introduce events etc.
Comment #140
kim.pepperSince we've agreed we're not going down the event route just now, here's a re-roll of #124 to get us back on track.
Comment #141
berdirPer #127 and #138, lets try this again with the previous approach. We have issues in #139 to improve DI and avoid circular dependencies, until then, I think going with the full DI approach would be extremely challenging.
Comment #142
larowlanI have pinged the security team for a review of the removed call in every prepareDestination
Comment #143
mcdruid commentedIn #98 Berdir asked if it's okay to remove the call to "ensure" from
prepareDestination().One argument for ensuring that the .htaccess files are in place in the main files directories (/ stream wrappers) regularly is that it's not uncommon for (e.g. object injection) exploits to be able to delete files.
If this happens and the .htaccess in the top of the public files directory is removed, an attacker may then be able to upload php files which the webserver would execute (in certain configurations).
Ensuring that the top-level .htaccess is in place before every upload mitigates this risk.
If that's removed, what else regularly ensures that the main files directories are protected? Per larowlan (in slack) it looks like with the patch from #140 the check is done on "a) status report b) install c) every admin/{system|config|help} etc page that uses the menu overview listing".
Perhaps that's sufficient in many cases, but it's not hard to imagine a site which would become more vulnerable as a result of this change.
If it's problematic (because of dependencies) to do the check from
prepareDestination(), one option may be to add a check on cron runs? Not a perfect replacement, but it would offer a little extra protection.Comment #144
mcdruid commentedPatch which adds the htaccess check to
system_cron().I did also consider adding it to
file_cron(), but we run this check fromsystem_requirements()at runtime, and notfile_requirements().You could possibly argue either way.
Let's see whether tests are okay with it added to
system_cron().If we want to keep this, we should add a test which removes a .htaccess file and then runs cron, to ensure it gets added back in again.
Comment #145
mcdruid commented\Drupal\KernelTests\Core\File\DirectoryTest::testFileCheckDirectoryHandlingalready has this:We could add another test which does the same thing but runs cron instead of calling
ensure()directly.I'm happy to work on that, but will wait for further (security) review before doing so.
Comment #146
mile23Hey folks. Not to be a downer here or anything... But.. :-)
In #3057094-101: Add Composer vendor/ hardening plugin to core we need to be able to generate htaccess and web.config files to place within the vendor directory in a Composer plugin context (meaning: No Drupal core.) If we don't change anything about how
drupal/core-php-storageworks, then we're golden. However:In #3013210-4: Add drupal/core-filesecurity component for writing htaccess files there's the thought of further teasing this htaccess behavior out into its own component.
The thing is, we need to do one or the other, sooner rather than later, so that we can progress on the Composer initiative. #3057094: Add Composer vendor/ hardening plugin to core is now blocked on #3013210: Add drupal/core-filesecurity component for writing htaccess files, which could also mean being blocked on this issue.
We're blocked because we want to build a Composer project template, and once that template out in the wild, it might well be tricky for users to update if our Composer plugin suddenly has different dependencies than the lock file they committed.
Personally I'm +1 on making another component that only knows how to make htaccess files in #3013210: Add drupal/core-filesecurity component for writing htaccess files, and decorating it as a service in this issue.
Comment #147
kim.pepperYeah I think that makes the most sense. There is so many dependencies in here that there's no way a replacement for file_ensure_htaccess() and file_save_htaccess() can be done with a component alone.
Postponing on #3013210: Add drupal/core-filesecurity component for writing htaccess files
Comment #148
kim.pepperIf/when #3013210: Add drupal/core-filesecurity component for writing htaccess files goes in I think we can replace lots of usages of
file_save_htaccess()with justFileSecurity::writeHtaccess()component calls, rather than calling this new service. The component has zero dependencies, whereas this depends on StreamWrapperManager, FileSystem, and Logger adding a lot of complexity for such a low-level service.The only differences now are:
This code allows you to provide a stream wrapperLet's do a review as part of this issue once the FileSecurity component lands.
Comment #149
kim.pepper#3013210: Add drupal/core-filesecurity component for writing htaccess files just landed 🎉
Comment #150
kim.pepperHere's a re-roll of #144.
I like the cron idea!
Comment #152
kim.pepperFixes test due to error message in dblog, trying to get the realpath() when calling \Drupal\Core\File\HtaccessWriter::ensure(). We don't need to use the realpath for file_put_contents().
This means we can remove file_system as a dependency of HtaccessWriter! 🎉
Comment #153
kim.pepperOops. Forgot to use $this->logger().
Comment #154
kim.pepperSo now
HtaccessWriter::save()is just:I'm wondering how we provide guidance around when to use
HtaccessWriter::save()over justFileSecurity::writeHtaccess()?Comment #155
andypost@kim.pepper thanks! code looks much more clear now!
Btw looking through usage it looks there only 2 public methods needed for each directory ("ensure" + "getState") + internal "write" can catch real file system exceptions and use logger.
The static list (public, temp) ... [private] all could be declared in file_system as core defaults so writer can read it there.
Better to convert array to valueObject... kinda
fileSytem::getFileSecurity($dir...)then use its methods ensure() and status() (which is used a lot in system module)Comment #156
kim.pepperThanks @andypost
I've moved
HtaccessWriter::save()to a protected method (and re-named towrite()). I've also updated thefile_save_htaccess()deprecation message to refer people to FileSecurity. However, we still need to maintain BC so I've duplicated the streamwrapper normalize call and logging in the deprecated function.I've also replaced usages in
system_check_directory()to callFileSecurity::writeHtaccess()directly, as we a showing form errors if there is a problem.I also liked the idea of a value object, so created
\Drupal\Core\File\ProtectedDirectoryand re-wrotegetHtaccessFiles()todefaultProtectedDirs()that returns aProtectedDirectoryobjects.Let's see how this goes!
Comment #157
kim.pepperForgot to mention I didn't move this to FileSystem, as I wanted to avoid having HtaccessWriter depend on FileSystem and re-introduce the circular dependency!
Comment #159
kim.pepperReplace use of
HtaccessWriter::save()withFileSecurity::writeHtaccess()insimpletest.install.Comment #161
kim.pepperA couple of fails since
htaccessWriter::write()was made protected. Changed it to public and@internalinstead.Comment #162
andypostThis is only places where "private" used, but in most places directory is known when private
I mean uri already has "private://"
So second argument could be removed and only "overwrite" is a question
I bet first line not needed
Comment #163
kim.pepperComment #164
imyaro commentedStill no progress?
Point #1 - agree with kim.pepper, we should leave an ability to mark custom directories outside the private:// as "Private"
andypost the rest is OK for you?
Comment #165
kim.pepper@zvse feel free to review and mark rtbc if you feel it is ready!
Comment #166
jibranI think the patch is ready now.
Comment #168
kim.pepperTestbot wooble
Comment #169
imyaro commentedFrom my side:
1. I don't think that defaultProtectedDirs is correct method name. it is not default directories, it is kind of list of directories
Probably "getProtectedDirs" will be better.
2. No interface for the ProtectedDirectory
I think we need it to determine which methods are required and which are not. It will help us to develop custom protected directories
3. We don't have a chance to add new ProtectedDirectory without overriding the file.htaccess_writer service. Probably it is OK, but I love flexibility
Changing to needs work mainly because of #2
Comment #170
kim.pepperHtaccessWriter::ensure()is only meant to be used to protect known core directories of public, private, and temporary. Any core/contrib modules that want to protect other directories should use the\Drupal\Component\FileSecurity\FileSecurity::writeHtaccess(), as we are did in #3057094: Add Composer vendor/ hardening plugin to coreComment #172
kim.pepperMore testbot glitches.
Comment #173
larowlanPinged the security team again about a final review and removing the needs security review tag
Comment #174
kim.pepperUpdated change record and issue summary to explain that
file_save_htaccess()is deprecated in favour of\Drupal\Component\FileSecurity\FileSecurity::writeHtaccess().Comment #175
mcdruid commentedOne more thing I'd add is a basic test to ensure that cron restores a missing .htaccess - I've added that (per #145).
If tests pass, I'll move it back to RTBC and remove the "needs security review" tag.
Comment #176
mcdruid commented:thumbsup:
Comment #177
larowlanComment #179
larowlanCommitted d8ec05c and pushed to 8.8.x. Thanks!
🎉 thanks everyone for hanging in there on this one!
published the change record