Skip to main content
Topic: Plugin uploading (Read 7295 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Plugin uploading

I feel like sharing what I've been doing. I don't know where your plans are with plugins, exactly, or even what the plans are but I'm assuming you have done (or are going to do) the same thing I did with Wedge: disable the ability of plugins to make core file edits, or at least severely curtail it. I feel that's a safe assumption to make based on the strategic way everything appears to be being arranged for Elk.

On that assumption, then, I came up with this bat**** crazy method of solving permissions. I have today been able to upload plugins to a regular shared server, where all the files and folders are chowned by the regular user, where all files/folders remain at 644/755, and where the newly uploaded files are also owned by the regular user. Not a single chmod in sight anywhere.

I can't directly share code (we're not into that permissive licence territory yet, though we're getting there... baby steps and all that) but I can share the methodology with you. I'm not saying you have to take it or anything. I just want to share what I did, because it might be of interest to you.

The file is uploaded via conventional upload dialogue in the ACP (much like upload package is in SMF), the file is moved into the cache folder (the only folder I can be assured will be writable and whose contents are implicitly implied to be volatile, no more so than system /tmp), and the zip file is assessed. We only support zip, but for one good reason: we don't unpack it at any point.

Here's where it gets hairy. We never unpack it, we step through the file - because it's a non-solid archive, we can pull files at will without ever having to unpack the entire archive. Thus we never have to write it anywhere in the interim - prevents it being tampered with from outside. (There are other measures, like tracking the size and md5 of the file, and if it differs, abort with a 'tampered with' message)

Because we can handle it with individual files, there is nothing to stop us uploading those files through FTP - as if the user did it themselves. So that's exactly what we do - we get the user's FTP details and instead of using that to chmod anything, we use that to actually perform the upload of the files - unpacked from the zip directly into memory, sent off directly over FTP. It's ugly, but it has shown to work; I get all my plugin files unpacked, quite happily, into the Plugins/myplugin (or wherever) folder - and they're all appropriately owned and have standard upload permissions, which means inheriting the usual system defaults.

Of course this doesn't work on a localhost, but then you can just drop plugins entirely in their own folder into Plugins/ anyway :/

Anyway. I spent way too long figuring all this nonsense out and I'm satisfied with the result. It might prove useful or interesting to someone here. It might not, but hey, we can share ideas :)

Re: Plugin uploading

Reply #1

Really cool work! I just saw the notes on wedge on this. It must have taken you a lot of work, but avoiding permissions issues makes it sound all worth it, and the result for the usability of plugins uploading.
Did you base the zip traversal on an existing library/code? I've read something to this effect at some point, but I'm not sure you kept it.
Thanks for sharing notes. :)
The best moment for testing your PR is right after you merge it. Can't miss with that one.

Re: Plugin uploading

Reply #2

The hardest part, oddly enough, was figuring out FTP - SMF (and thus both Wedge and Elkarte) bundles a usable FTP library but it doesn't have methods for putting content to a server, nor does it support enhanced passive connections (i.e. FTP over IPv6), which are the biggest hurdles to this. I'm not even sure if the get method for downloading a file was even present, now that I think about it. I have a vague recollection of adding other utility methods such as getting a raw directory listing, but I forget how much of that was originally SMF code, I haven't checked.

The zip traversal is actually my own library, built specifically for parsing and extraction. I was originally going to use PclZip, but PclZip is very big (199KB, though I did manage to get it down to 80KB through cleaning it up) and from my perspective bloated; the entirety of it reads like a C script, every method returns a number indicating success (0 for success, any other number for error) and everything is otherwise passed by reference, and since that means everything is using $v_ and $p_ prefixes on everything (indicating local variable vs foreign pointer/reference), I found it largely unreadable.

I threw a lot of zip files at the new class (which is barely 18KB) and couldn't get anything to break it that shouldn't break it, but you never know heh.