request: documenting a nice local dev setup for smf

Started by viviridian, Apr 11, 2025, 01:52 AM

Previous topic - Next topic

viviridian

it'd be nice to have instructions for setting up and hacking on smf locally with the packages we have here. i'll *probably* do this myself, just making a thread to track the idea

snow

I've wanted to do that for a bit, just have lacked the motivation to write the docs. If you do end up doing this, let me know if there's any extra info you need!

Security config aside, it's a pretty standard nginx/mariadb/php-fpm setup. I need to get that one "attach lightbox" patch converted to a proper SMF mod, which I'll get to... eventually.

viviridian

I got a basic LAMP setup running in rootless podman. Any method of getting a LAMP stack is viable, a nice quality of that approach is that it is both contained & doesn't require fiddling with permissions if you want to poke smf's files.

1. Set up some kind of webserver with php and a database (e.g. the above thing)
2. Download SMF and unpack it somewhere in the webserver. Navigate to it in your browser and go through setup. (see instructions in my repo for more detail)
3. Clone the f9 repo.
4. Run make. The `out` dir should now contain packages.
5. In SMF go to the admin panel, and then to Package Manager > Add Packages
6. Upload each package except for the theme. Install each of them.
7. In the admin panel go to Configuration > Themes and Layout > Manage and Install
8. Under 'Install a New Theme', upload the theme's zip to install it. IMPORTANT: DO NOT SWITCH THE FORUM'S DEFAULT THEME YET.
9. Go to 'Theme Settings', and click the gear icon for 'f9_theme'. (If you did switch to the new theme, you'll have to switch back. or view source and get the hyperlink for the gear icon, which will be missing :) )
10. Update both "This theme's URL" and "This theme's images URL" to both refer to `f9_theme` instead of `default`.
11. Also change the default smiley set for the theme to F9.
12. Now change the forum default them to f9_theme.

Open question: what's the most efficient way to iterate on the packages? I assume you aren't rebuilding the packages and uploading them through the admin panel each time (...?)

viviridian

i could have used some more fully-featured container someone else already built (such as https://github.com/8ctopus/php-sandbox) but that wouldn't satisfy my drive to do things the hard way

snow

Quote from: viviridian on Apr 13, 2025, 09:23 AMOpen question: what's the most efficient way to iterate on the packages? I assume you aren't rebuilding the packages and uploading them through the admin panel each time (...?)

ehehe.jpg

Typically I only take that route if I'm doing something with install hooks. Modifying the F9 theme is easiest since everything in the folder takes effect by default, but if you need to add a new hook or are modifying on-install behavior, it needs to be reinstalled. I've considered modifying the database directly (it's not that bad for (un)installing hooks), but the uninstall/reinstall method was easiest for the time being.

Typically what I'll do is SSH into my sandbox server and modify the files directly in the locations they got installed to, and then scp them back when I'm done.

As I write this out, I think for a Docker container it wouldn't be too hard to write a wrapper script that handles reuploading the package to the container, so long as the manifest doesn't change much. It could also help with the initial setup. I'd have to play with the idea when I have a chance to know if it has any chance of working, though.

viviridian

for reference, I captured the steps involved in removing and uploading a package as fetch() calls (TIL firefox dev tools let you copy web requests as fetch calls!)


// Click package uninstall button
await fetch("http://localhost:8000/smf/index.php?action=admin;area=packages;sa=uninstall;package=yt_nocookie.tar.gz;pid=6", {
    "credentials": "include",
    "headers": {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Sec-GPC": "1",
        "Upgrade-Insecure-Requests": "1",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "same-origin",
        "Sec-Fetch-User": "?1",
        "Priority": "u=0, i"
    },
    "referrer": "http://localhost:8000/smf/index.php?action=admin;area=packages;b351fce7=26041204f38b96a8c3b881969eccb5e0",
    "method": "GET",
    "mode": "cors"
});

// Click uninstall now button on that page
await fetch("http://localhost:8000/smf/index.php?action=admin;area=packages;sa=uninstall2;package=yt_nocookie.tar.gz;pid=6", {
    "credentials": "include",
    "headers": {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Content-Type": "application/x-www-form-urlencoded",
        "Sec-GPC": "1",
        "Upgrade-Insecure-Requests": "1",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "same-origin",
        "Sec-Fetch-User": "?1",
        "Priority": "u=0, i"
    },
    "referrer": "http://localhost:8000/smf/index.php?action=admin;area=packages;sa=uninstall;package=yt_nocookie.tar.gz;pid=6",
    "body": "b351fce7=26041204f38b96a8c3b881969eccb5e0&seqnum=771751",
    "method": "POST",
    "mode": "cors"
});

// Delete the package's file so it can be replaced
await fetch("http://localhost:8000/smf/index.php?action=admin;area=packages;sa=remove;package=yt_nocookie.tar.gz;b351fce7=26041204f38b96a8c3b881969eccb5e0", {
    "credentials": "include",
    "headers": {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Sec-GPC": "1",
        "Upgrade-Insecure-Requests": "1",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "same-origin",
        "Sec-Fetch-User": "?1",
        "Priority": "u=0, i"
    },
    "referrer": "http://localhost:8000/smf/index.php?action=admin;area=packages;sa=browse;b351fce7=26041204f38b96a8c3b881969eccb5e0",
    "method": "GET",
    "mode": "cors"
});

// Upload a new version of the package
await fetch("http://localhost:8000/smf/index.php?action=admin;area=packages;get;sa=upload", {
    "credentials": "include",
    "headers": {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Content-Type": "multipart/form-data; boundary=----geckoformboundarye29a7e416a08ac88515f9800cf9a065b",
        "Sec-GPC": "1",
        "Upgrade-Insecure-Requests": "1",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "same-origin",
        "Sec-Fetch-User": "?1",
        "Priority": "u=0, i"
    },
    "referrer": "http://localhost:8000/smf/index.php?action=admin;area=packages;sa=packageget;get;b351fce7=26041204f38b96a8c3b881969eccb5e0",
    "body": "------geckoformboundarye29a7e416a08ac88515f9800cf9a065b\r\nContent-Disposition: form-data; name=\"package\"; filename=\"yt_nocookie.tar.gz\"\r\nContent-Type: application/gzip\r\n\r\n\u001f�\b\u0000\u0000\u0000\u0000\u0000\u0000\u0003íW[oÛ6\u0014ö³�Å�`ÔÝ:�R|C3É)°åqí�d\u000f�a\u0018´DÙ�%Ñ%)_:ô¿÷P�\u0013ÛHà\u000eHR\fã÷`I¼|ç�<üαK\u001a/\u000e\u000f1ì÷ÍÓ\u001fö½Ãç\u001e\r¿7\u001c\u000e\u0006ÃAÏë6<ß\u001btû\r迼k�F¡4�\u0000�5_§<{zܹþÿ(\\rSÌTçN�\u0014�$�óÜ]-VÏlÃ\u001cð ×{êü}¯wqrþ½®?h�÷Ì~<�ÿùù\u0007WxÞÍfRä�æ\"�
\u0010ËéNOs!Êpxû¦\u0015��©_áM+\u0017SZh�ò|9Õt®~����h%¢Èc\b!¡©b¿Um<Þb�W}%B2\u001a-àmE\u0006TAù¶g0àIÝ=n#y{\u0002a\bí�(t1cíÃ�G&µ,j�{ÌÐÔò¡éëý�qéÝ»ª§j-M�L�ü�Àõ�É�^ð|\u000el\u001b±��«j;Â\u0007¶r%cC:\u0019·#�k�kã5´��¯!J©R¡³æ1\u0013¦�ò�IgdúF\u0001O$Í\u0018�¿3!c&CÇs@É(t\u0016Z¯Ô%!�ÍÆ��ßÉ�B,9s#�\u0011�ÍXLZþÕ&C\u0017B±¢�\u000bæ@L5íì'ð8tZ¾\u00034MÅ&)ÒTE�±\u001cRAc\\Uè¤ôË\u000e½!�'øRúUþ¶÷[ôµÙ¼\u001a5�t�Z¼$\\²¢Ñ�Î1dòD¸Û,}~\u001bçô�à\rOô¿;Ä&«ÿ¯�à\n�\u001cPî\u0014ª�èø®çà�\u000f~úãÓï·w�]ÃatÀÍÝÍíõ�PJT�P�g«�e(î¨oÊ\u0015rN�ð(¨\u001cä;¢Á\u0001¹\nÿ-K5íReɹ©hÐ\bXÀãÑ�$-¤Ü]�\u0019�ÒPÔ¼¸\u001e�\u001béû[18ÕY�°àN\u0014·Ø\u0018�rX5£Þ¨\u0011îS@ö\u001fU�Þ�Ø\b\u0015�'<¢&�\u0006¤ljÖÎä\u0018hij�CçÂõÝ_ \u0003æùþ}ío9\f�W��aE¥b³\u0019¦\u0003�à�QÕìê�\u000eHõ~4çsÁ%ë$<e`�\r�G�:Ì\u0010Li��¾avP¢�\u0011�¹t�\u001c��\u0002 ¬\u0002B�cN�KªÙ\u0014=��ùÎ�}¥��pR*`\u001f:pÈüXmyo\rÏ¡Ú�ý\u000e\u0015ùwïQ&ÖGËýN�¯´@ÉLd°úì\u001eÖ{¿@¼\u0010G±ý\u0003�¬K\u001eBë¥l�Ñ�ïbè�èÿÅ Ûµúÿ\u001a\u0018+þ

ÛNJå�MƳÉ99\u001c�ÙdL̬I³y»à\nªë¨@/\u0018 A](�q�
©Ü\u00191Ã[ª�Ä�Wd{\"(ëXücA±�/\u0014\u0012�«|K7ªY®-K-,,,,,,,,,,,,,,,,,,,,,�Æ7¹|·`\u0000(\u0000\u0000\r\n------geckoformboundarye29a7e416a08ac88515f9800cf9a065b\r\nContent-Disposition: form-data; name=\"b351fce7\"\r\n\r\n26041204f38b96a8c3b881969eccb5e0\r\n------geckoformboundarye29a7e416a08ac88515f9800cf9a065b--\r\n",
    "method": "POST",
    "mode": "cors"
});

// Click install mod for the new package
await fetch("http://localhost:8000/smf/index.php?action=admin;area=packages;sa=install;package=yt_nocookie.tar.gz", {
    "credentials": "include",
    "headers": {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Sec-GPC": "1",
        "Upgrade-Insecure-Requests": "1",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "same-origin",
        "Sec-Fetch-User": "?1",
        "If-Modified-Since": "Sun, 13 Apr 2025 09:05:11 GMT",
        "Priority": "u=0, i"
    },
    "referrer": "http://localhost:8000/smf/index.php?action=admin;area=packages;get;sa=upload",
    "method": "GET",
    "mode": "cors"
});

// Click install now for the new package
await fetch("http://localhost:8000/smf/index.php?action=admin;area=packages;sa=install2;package=yt_nocookie.tar.gz;pid=0", {
    "credentials": "include",
    "headers": {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Content-Type": "application/x-www-form-urlencoded",
        "Sec-GPC": "1",
        "Upgrade-Insecure-Requests": "1",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "same-origin",
        "Sec-Fetch-User": "?1",
        "Priority": "u=0, i"
    },
    "referrer": "http://localhost:8000/smf/index.php?action=admin;area=packages;sa=install;package=yt_nocookie.tar.gz",
    "body": "b351fce7=26041204f38b96a8c3b881969eccb5e0&seqnum=8868160",
    "method": "POST",
    "mode": "cors"
});

viviridian

so perhaps for development i could stand up a sidecar web server that publishes the built packages, and add some client-side javascript that polls that and swaps out new packages as they become available

viviridian

I had a better idea: write a "smart" reverse proxy to mitm the server -- that way I would definitely have access to an authenticated session and be able to issue requests from that server *or* the client.

I could also inject stuff into the page, like a script tag or button(s), allowing smf to be extended without having to actually fiddle with the codebase.

snow

Finally put aside some time to look at the SMF-Docker repository-- this looks really good!

Would it be alright with you if I submitted some PRs? I've built out a PHP script to auto-configure SMF, and also had to make some configuration changes so it'd work on my end.

viviridian

Quote from: snow on Apr 18, 2025, 04:19 AMFinally put aside some time to look at the SMF-Docker repository-- this looks really good!

Would it be alright with you if I submitted some PRs? I've built out a PHP script to auto-configure SMF, and also had to make some configuration changes so it'd work on my end.
sure, go for it!

i started poking at building a reverse proxy in python. it's *kinda* working aside from POST requests, I'll probably leave that for later and focus on the more interesting main quest of "install updated versions of locally built packages"