148 Commits
3.0 ... master

Author SHA1 Message Date
root
6f709886ed added terminal interface as default. old website as no-js fallback 2026-01-21 09:58:53 -07:00
deepend-tildeclub
81d9ddfd03 Merge pull request #2 from l0v3ris/update-code-links
update code links to point to github instead of tildegit
2026-01-13 11:15:05 -07:00
c74cd91ab3 update code links to point to github instead of tildegit 2026-01-13 10:34:26 -07:00
deepend-tildeclub
ca2f3df587 Merge pull request #1 from l0v3ris/master
fix donate link and minor copy update
2026-01-13 10:19:23 -07:00
d02152e2b8 fix donate link and minor copy update 2026-01-10 07:17:39 -07:00
root
9d38dd8ede minor fixes/updates 2026-01-09 10:39:50 -07:00
deepend-tildeclub
ae59561267 Create FUNDING.yml 2025-07-23 10:14:00 -06:00
deepend-tildeclub
f9129eefc7 Update privacy.md 2025-04-26 13:44:16 -06:00
deepend-tildeclub
e3c3205016 Update sidebar.md 2025-04-26 13:42:55 -06:00
deepend-tildeclub
0e07cc3b01 Rename gdpr.md to privacy.md 2025-04-26 13:42:19 -06:00
deepend-tildeclub
bf8fef650b Update gdpr.md 2025-04-26 13:41:55 -06:00
deepend-tildeclub
281ca362bd Update news.md 2025-04-26 13:29:45 -06:00
deepend-tildeclub
7c620cbe55 Update server.md 2025-04-26 13:27:19 -06:00
deepend-tildeclub
2ae6c8c2b8 Update users.php 2025-04-26 13:17:26 -06:00
deepend-tildeclub
b4b26fcc67 Update tos.md
updated TOS.
2025-04-26 13:16:13 -06:00
deepend-tildeclub
a959fe100f Update users.php
fixes user listing.
2025-02-13 19:03:39 -07:00
deepend-tildeclub
b882fd6bf3 Update main.md 2024-12-01 21:37:13 -07:00
deepend-tildeclub
e9cc392d16 Update newthunix.css 2024-12-01 21:35:59 -07:00
deepend-tildeclub
e65540137e Update sidebar.md
re-ordering items
2024-11-30 14:33:17 -07:00
deepend-tildeclub
a9f3f8f43c Update news.md
Gemini
2024-11-30 14:01:29 -07:00
deepend-tildeclub
8ffde3c0f8 Update faq.md 2024-11-28 12:44:08 -07:00
deepend-tildeclub
42bf107686 Update copyright.md 2024-11-28 12:41:39 -07:00
de2c993957 Update includes/footer.md 2024-03-25 02:53:13 +00:00
08f9258f5c Update articles/server.md 2024-03-25 02:49:49 +00:00
cb8a7c00ec Update articles/server.md 2024-03-25 02:48:56 +00:00
5fd94f5487 update includes/signup.php 2024-03-25 02:29:18 +00:00
33ad7a37ae change to Newnet and update ssh fingerprints 2024-03-25 01:32:36 +00:00
127a63d4a4 change to Newnet 2024-03-25 01:22:50 +00:00
31dfa8fc34 Update includes/signup.php 2024-01-23 04:23:45 +00:00
0138a6e12d Update githook.php 2024-01-02 20:55:37 +00:00
bd705ab55d Update humans.txt 2023-12-27 06:58:34 +00:00
1456e013ec Update includes/sidebar.md 2023-12-27 06:55:06 +00:00
34a344a952 add ssh fingerprints (fixed) 2023-08-02 15:08:14 +00:00
99c00eb649 add ssh fingerprints 2023-08-02 15:06:37 +00:00
e3a380be10 Update 'articles/server.md' 2023-07-10 15:16:35 +00:00
65b13d8949 changed BZFlag server status 2023-07-08 20:01:43 +00:00
Naglfar
610904d4b9 Update znc port 2023-07-08 12:37:55 -06:00
9dcb1906f9 Update 'articles/server.md' 2023-07-06 19:38:06 +00:00
5b74ae2415 Update 'articles/main.md' 2023-07-04 20:29:59 +00:00
5e95451c0e Update 'articles/faq.md' 2023-07-04 20:28:08 +00:00
23288a99b4 Update 'articles/news.md' 2023-07-04 20:25:04 +00:00
4af70552f5 Update 'articles/donate.md' 2023-07-04 19:48:41 +00:00
a5c0980f3a Update 'articles/server.md' 2023-07-04 19:41:10 +00:00
153adcfdd1 Update 'githook.php' 2023-07-04 18:03:40 +00:00
Naglfar
269bd5ea1f Replace Email Address with the Return Address 2022-03-08 18:31:21 +01:00
Ubergeek
db7b6282ce temp change of unicode chars in title 2022-02-28 14:06:08 -05:00
Ubergeek
5ef05e811e Fixed chat link 2022-02-11 14:17:29 -05:00
ubergeek
ef89333873 just some cleanup of the webhook code 2022-02-07 12:51:21 +00:00
Ubergeek
a7f799912b Merge branch 'master' of ttm.sh:thunix/www 2022-02-06 13:01:48 -05:00
Ubergeek
425641da57 Updated tor addr to v3 addr 2022-02-06 13:01:30 -05:00
Naglfar
eb8b5b6f74 Print href only for updated contents 2021-12-14 10:01:53 +01:00
Naglfar
b8545fb767 There is an index.html already 2021-11-18 17:13:06 +01:00
Naglfar
860d816031 Print href only for updated contents 2021-11-18 13:36:15 +01:00
Ubergeek
2ffb79088f updated tilde.json 2021-10-08 07:46:54 -04:00
Ubergeek
4ea46e4e24 updated tilde.json 2021-07-08 20:07:34 -04:00
Naglfar
73f0a980d9 Do not list empty directory 2021-06-18 10:50:31 +02:00
Naglfar
16f9b6e4a6 Not always contents are listed just with index.html or index.php 2021-06-18 10:38:26 +02:00
Naglfar
55f641afc4 List non-empty user web directories 2021-06-17 16:49:58 +02:00
Naglfar
99b9d67af0 Execute statement if expression evaluates to true 2021-06-17 16:26:44 +02:00
Naglfar
f9dd82d909 Update about Thunix 2021-05-17 16:00:07 +02:00
ubergeek
44508f99dc updated IP 2021-04-28 15:10:08 +00:00
Naglfar
f5aaed23ab to remove new line characters from a DOS file 2021-03-20 04:57:52 +01:00
Naglfar
d36f10189d Statements grouped with curly braces 2021-03-12 17:46:39 +01:00
Naglfar
cfd6ccdbbc Username passed lowercased once 2021-03-01 19:27:46 +01:00
Ubergeek
0833e91520 Starting making user adds more automated 2021-02-27 20:49:07 -05:00
Anton McClure
fce23c7cd1 Fix typo in license link 2021-01-16 17:44:22 +00:00
Naglfar
1b9c4e87af Let wiki.php render server.php 2021-01-12 22:00:42 +01:00
Naglfar
a6ae512417 Let wiki.php render users.php 2021-01-12 21:42:55 +01:00
Naglfar
48922db7c4 Avoid undefined variable warnings in wiki, users and server pages 2021-01-12 16:00:14 +01:00
Naglfar
107ea4f396 Make the cursor blink 2021-01-05 01:03:08 +01:00
Naglfar
d163822726 Avoid warning undefined variable 2021-01-04 20:28:25 +01:00
Naglfar
fa3e7ed385 Remove left edge from image 2020-12-28 00:33:52 +01:00
Naglfar
58e54f5f01 Delete duplicate content 2020-12-28 00:25:30 +01:00
Naglfar
99f93eb00e Update web hosting service description 2020-12-28 00:19:44 +01:00
Naglfar
8122e8d4a0 Add account recovery to FAQ 2020-12-26 22:31:20 +01:00
Naglfar
7a30f92ed1 Add hyphens to highlight dialogs 2020-12-26 20:45:38 +01:00
Naglfar
278f561744 Add specific error page public key format 2020-12-22 20:08:44 +01:00
Naglfar
1dde4d4fc1 Comment added to the Tor service 2020-12-16 19:08:49 +01:00
Naglfar
86f04da9a4 Edit web server information 2020-12-04 11:02:27 +01:00
Naglfar
75ab2e6a94 Adding web server information 2020-12-04 10:53:08 +01:00
Naglfar
e83a255b85 Main Menu update 2020-11-23 10:39:54 +01:00
ubergeek
74a3c9a45d Merge pull request 'Pages link to thunix/www repo and the specific page's .md file' (#30) from amcclure/thunix-www:master into master
Reviewed-on: https://tildegit.org/thunix/www/pulls/30
2020-07-03 13:56:30 -04:00
Anton McClure
fc73f8c4df add site and page source links 2020-07-03 13:18:58 -04:00
ubergeek
c8e6df0083 Merge pull request 'Updating TOS' (#29) from ubergeek/www:master into master 2020-05-08 12:48:16 -04:00
Naglfar
d720fd3758 Check SSH public key format 2020-05-07 13:34:14 +02:00
Naglfar
bc6c6d735b Check if username already taken 2020-05-07 12:03:45 +02:00
Naglfar
495d05679d Only check everything else if it's not a spam attempt 2020-05-07 11:57:18 +02:00
Naglfar
c7a949f04f Verify the form data and proceed if applicable 2020-05-06 23:00:27 +02:00
ubergeek
4076b295a5 full stops 2020-04-30 10:34:36 -04:00
ubergeek
bd947c1c5a tweak 2020-04-29 22:37:20 -04:00
ubergeek
eee94058a1 updated TOS 2020-04-29 22:36:08 -04:00
Ubergeek
8e1c0f38b7 Removed extraneous footer material 2020-03-11 08:11:49 -04:00
Ubergeek
069e01fe6a Merge branch 'master' of ttm.sh:thunix/www 2020-03-11 08:09:32 -04:00
root
3e7cd1b41f Updated news, and footer 2020-03-11 08:09:20 -04:00
ubergeek
e2d7a5a8d3 Update 'githook.php' 2020-03-09 19:26:46 -04:00
ubergeek
cd7b28cd30 added sponsor tag 2020-03-02 21:25:57 -05:00
Ubergeek
f55fe3f58e State of the Thunix Feb 2020 2020-02-03 08:26:35 -05:00
Ubergeek
ba8870e5a3 Merge branch 'master' of ttm.sh:thunix/www 2020-01-11 20:08:36 -05:00
Ubergeek
6c0e749edb updated allowed IP for hook 2020-01-11 20:08:20 -05:00
ubergeek
77136affc2 Merge branch 'css-change' of khuxkm/www into master 2020-01-10 08:38:58 -05:00
Robert Miles
d0c4b91965 Make link colors apply globally
Visited links in the footer fail accessibility guidelines. This should fix that.
2020-01-10 08:37:37 -05:00
Ubergeek
3940d7139f Merge branch 'master' of ttm.sh:thunix/www 2020-01-03 00:44:42 +00:00
Ubergeek
0c4465e827 state of the thunix jan 2020 2020-01-03 00:44:26 +00:00
ubergeek
df35168d78 Merge branch 'master' of anton/thunix-www into master 2019-12-31 19:07:26 -05:00
Anton McClure
f8bc4e33e8 Fixed error with email links 2020-01-01 00:00:00 +00:00
Ubergeek
5497ab7a96 Adding lumen address for donations 2019-12-11 22:13:59 +00:00
Ubergeek
85c2bbd372 Spelling corrections 2019-12-01 20:12:14 +00:00
Ubergeek
19f1d68c4f State of the thunix December 2019 2019-12-01 18:11:21 +00:00
Naglfar
31e121d1de Updated url to: how to make an ssh key 2019-11-20 20:11:04 +00:00
Ubergeek
53dff3d0c5 resized image 2019-11-18 14:53:02 +00:00
Ubergeek
5a320e18d4 Added link to list of contributors 2019-11-18 14:46:22 +00:00
Ubergeek
e4963556c0 Updated logo 2019-11-18 14:44:15 +00:00
Ubergeek
46ac9f3aa0 Added new logo, with better color scheme, and a redesign 2019-11-18 14:43:32 +00:00
Naglfar
e5392cefcb replaced shell_exec for php mail function 2019-11-12 17:48:17 +00:00
Ubergeek
cd6f3a0160 Making the failure page actually say failure 2019-11-12 13:39:24 +00:00
Ubergeek
972173f9e3 More better spelling 2019-11-07 13:06:37 +00:00
Ubergeek
78f3c86959 State of the Thunix for November, 2019 2019-11-07 13:02:49 +00:00
Ubergeek
43bcdbdad2 Cleanup 2019-11-05 15:58:23 +00:00
Ubergeek
a4fc0397e0 Updated gitignore to not manage tilde.json 2019-11-05 15:49:20 +00:00
Ubergeek
84a972ad55 Updated gen_tdp, with correct signup URL, and re-pushed tilde.json 2019-11-04 15:53:47 +00:00
Ubergeek
5072f073f6 Updated tilde.json 2019-11-04 15:43:19 +00:00
Ubergeek
f0ce076571 updated tdp 2019-10-27 18:45:44 +00:00
Ubergeek
58bcc89fc4 Adding client VPN service 2019-10-06 01:10:27 +00:00
Ubergeek
d7dc82cd9b State of the Thunix, October 2019-09-30 14:44:17 +00:00
Ubergeek
1aa16526d6 Updated tilde.json 2019-09-17 11:55:55 +00:00
Ubergeek
1f4e2d99e6 Updated tilde.json and header 2019-09-15 17:39:16 +00:00
Ubergeek
413317f930 updating site 2019-09-15 16:06:16 +00:00
Ubergeek
8466b31038 Updated tilde.json 2019-09-10 23:30:18 +00:00
Ubergeek
309f10a800 Updated tilde.json 2019-09-03 15:56:41 +00:00
Ubergeek
054698ee64 Updated sott for 09/19 2019-09-03 15:55:58 +00:00
Ubergeek
04db1ca0f0 Updating font 2019-08-07 13:07:30 +00:00
Ubergeek
73ec99f00b Adding font and fixing up css 2019-08-05 23:21:31 +00:00
Ubergeek
65fd3d2a71 flipping theme 2019-08-05 23:11:50 +00:00
Ubergeek
09bdd1a3fb Updated tilde.json 2019-08-01 19:28:13 +00:00
Ubergeek
6b068b06ad syntax fix 2019-08-01 17:56:12 +00:00
Ubergeek
43ee8347e7 state of the thunix for august 2019-08-01 17:55:38 +00:00
Ubergeek
f1e77a5973 Fixed chat link 2019-07-26 22:21:20 +00:00
Ubergeek
f4c566ca40 Adding a new testing theme 2019-07-24 01:07:37 +00:00
Ubergeek
80b32af16a Updated htaccess to allow for sitemap 2019-07-17 01:31:52 +00:00
Ubergeek
46cb6c4a3a Updated tilde.json 2019-07-17 01:28:57 +00:00
Ubergeek
dda7520818 Adding sitemap 2019-07-17 01:26:05 +00:00
Ubergeek
b269fe4476 adding the service report to gitignore 2019-07-15 16:50:39 +00:00
Ubergeek
34da0f2242 Corrected report location 2019-07-15 16:44:00 +00:00
Ubergeek
328fb17482 Cleanup of invalid html tags 2019-07-15 16:39:59 +00:00
root
e529f5b691 Fixing docroot 2019-07-15 13:56:56 +00:00
Ubergeek
316f39401f Flipping to minified thunix.css 2019-07-15 13:54:29 +00:00
Ubergeek
8a3cdb48f5 First 3.0 to master 2019-07-14 00:45:32 +00:00
Ubergeek
2810791c00 updating tilde.json 2019-07-08 22:43:56 +00:00
49 changed files with 3836 additions and 472 deletions

5
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
# These are supported funding model platforms
ko_fi: tildeclub # Replace with a single Liberapay username
github: tildeclub
custom: https://www.paypal.com/donate?hosted_button_id=DWHSADKJ26HZ8
custom: https://donate.tilde.club

3
.gitignore vendored
View File

@@ -1,2 +1,5 @@
*.swp *.swp
webmail webmail
includes/report
report
tilde.json

View File

@@ -1,7 +1,23 @@
RewriteEngine On RewriteEngine On
RewriteRule ^$ main [QSA]
RewriteRule ^index\.php$ wiki.php?page=main [QSA] # Classic query-style links like /?page=main should keep working.
RewriteRule ^users$ includes/users.php [QSA,L] RewriteCond %{QUERY_STRING} (^|&)page= [NC]
RewriteRule ^server$ includes/server.php [QSA,L] RewriteRule ^$ wiki.php [QSA,L]
RewriteCond %{REQUEST_URI} !(/includes/|/media/|tilde.json|humans.txt|/webmail/|/favicon.ico|/~|githook)
RewriteRule ^([^\d]+)/?$ wiki.php?page=$1 [QSA] # Default experience: terminal UI.
RewriteRule ^$ terminal/ [QSA,L]
# If someone explicitly requests index.php with a page query, keep classic behavior.
RewriteCond %{QUERY_STRING} (^|&)page= [NC]
RewriteRule ^index\.php$ wiki.php [QSA,L]
# Otherwise, index.php also goes to the terminal UI.
RewriteRule ^index\.php$ terminal/ [QSA,L]
# Let real files and directories through untouched.
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Pretty URLs for wiki pages (no leading digit).
RewriteRule ^([^0-9][A-Za-z0-9_-]*)/?$ wiki.php?page=$1 [QSA,L]

View File

@@ -2,8 +2,8 @@ If you have any questions or problems relating to our service, or this website,
<form action='/includes/contact.php'> <form action='/includes/contact.php'>
<table> <table>
<tr><td>Contact Name:</td> <td> <input type='text' name='contact_name'><br></td></tr> <tr><td>Contact Name:</td> <td> <input type='text' name='contact_name'></td></tr>
<tr><td>Email Address:</td> <td> <input type='text' name='email_address'><br></td></tr> <tr><td>Email Address:</td> <td> <input type='text' name='email_address'></td></tr>
<tr><td>Subject:</td> <td> <tr><td>Subject:</td> <td>
<select name="type"> <select name="type">
<option value="abuse">Abuse</option> <option value="abuse">Abuse</option>
@@ -12,7 +12,7 @@ If you have any questions or problems relating to our service, or this website,
</select><br> </td></tr> </select><br> </td></tr>
<tr><td>Type the word tildeverse here:</td> <td> <input type='textarea' name='tv'></td></tr> <tr><td>Type the word tildeverse here:</td> <td> <input type='textarea' name='tv'></td></tr>
<tr><td>Message:</td><td><textarea name='message' rows = "10" cols = "80"></textarea><br><td> <tr><td>Message:</td><td><textarea name='message' rows = "10" cols = "80"></textarea><td>
</table> </table>
<input type='submit'> <input type='submit'>
</form> </form>

View File

@@ -1,5 +1,8 @@
## creative commons ## creative commons
# Contributors
A list of all contributors can be found here: [Commit log for Git Repo](https://github.com/ThunixdotNet/www/commits/branch/master)
# Attribution-ShareAlike 4.0 International # Attribution-ShareAlike 4.0 International
Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible.

View File

@@ -1,22 +1,13 @@
# Donations # Donations
As this server and our projects are all a labor of love and goodwill for the community, operating the thunix server costs money. We love what we do and we love sharing what we do for free, but over time, operating expenses can have a big impact. While this server and our projects are a labor of love and goodwill for the community, operating the thunix server still costs money. We love what we do and we love sharing what we do for free, but over time, operating expenses can have a big impact. In order to keep going, we rely on the good nature of generous people who are willing to donate to us. The price breakdown right now is €80/month.
That being said, we also rely on the good nature of generous people, who are willing to donate to us. The price breakdown right now is €38/month. So to help with server costs and time spent, you can donate the following ways: If you'd like to assist with server costs and help ensure we can spend time on the projects, you can donate in the following ways:
<div style="text-align:center;"> <div style="text-align:center;">
<p>Via BitCoin: 1DFM3qY7XmCxGTFPATSQJVCNjvmWiVubGN</p> <p>You can donate via fosspay here: <a href="https://donate.tilde.club/?project=2"><img src="https://www.gravatar.com/avatar/08ba2126a0dd0cb2efa30b854c7b4252?s=129"></a></p>
<p>You can donate via Liberapay here: <a href="https://liberapay.com/ub3g33k/donate"><img src="https://liberapay.com/assets/widgets/donate.svg"></a></p>
<p>Or via Paypal:</a>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_donations" />
<input type="hidden" name="business" value="GW2H85HY9VJ3L" />
<input type="hidden" name="currency_code" value="USD" />
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" title="PayPal - The safer, easier way to pay online!" alt="Donate with PayPal button" />
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
</form>
</p>
</div> </div>
_Be sure to select the thunix.net project in the dropdown and please add a comment to tell us your thoughts! Thank you!_

View File

@@ -2,38 +2,65 @@
**How do I sign up for an account?** **How do I sign up for an account?**
Simply by going to our [signup page](/signup) and filling in the form. You can ask for help in \#thunix on tilde.chat, or you can [contact us](contact), if you run into any difficulties. - Go to the [signup page](/signup) and fill out the form.
- If you get stuck, ask in **#thunix** on **newnet.net**, or [contact us](/contact).
**How can I request an account recovery or public key replacement?**
- Email us **from the address you used to register** and tell us:
- your username
- what you need (recovery / key replacement)
- your **new public key** (paste it in the email)
- Well swap the key and let you know when its done.
**Who is running thunix?** **Who is running thunix?**
The current system administrators are [amcclure](/~amcclure), [ubergeek](/~ubergeek), [Naglfar](/~naglfar), and [fosslinux](/~fosslinux). - Current system administrators: [deepend](/~deepend), [Naglfar](/~naglfar)
**What happened to the old thunix? Why the name change?** **What happened to the old thunix? Why the name change?**
The original machine and founder dissappeared without any warning to anyone, including server staff. For this reason, most things were not backed up, and we needed to obtain a new domain name, and a new set of machines. - The original machine and founder disappeared without warning (including to staff).
- Most things werent backed up, so we rebuilt on new machines and moved to a new domain.
**I want a new package installed, or I want something changed on Thunix!** **I want a new package installed, or I want something changed on Thunix!**
Excellent! We're looking to make this system useful for the community! You can submit a PR or an issue [here](https://tildegit.org/thunix/ansible) to request the system change. - Good. Thats how systems become useful instead of decorative.
- Ask in **#thunix** on **newnet.net**, or [contact us](/contact) with:
- what you want
- why you want it
- whether it needs to be available to everyone or just you
**Can I get password-based login? Old thunix had it!** **Can I get password-based login? Old thunix had it!**
No. Sorry. Not for shell access. For other integrated services, password auth will be enabled, but not for your ssh connection. We use key based authentication, as it's more secure, and more convienent for you, to be honest. - No. Not for **shell access**.
- SSH is **key-based** because its more secure and, honestly, less annoying once youre set up.
- Other services (like email) use passwords because thats how the world works.
**I want to run {fill in the blank} server, but I can't seem to access it?** **Thats too hard! Can you just open the port up for this service I have running?**
The only exposed ports to the internet are services as defined in our [ansible playbook.](https://tildegit.org/thunix/ansible) If there is a public service you want to see, open an issue, or do a pull request for it, and we'll probably enable it without much question. - No.
- If you need access to something youre running, use an **SSH tunnel**.
**That's too hard! Can you just open the port up for this service I have running?** - Example (adjust ports as needed):
- `ssh -L 8080:127.0.0.1:8080 youruser@YOUR_SSH_HOSTNAME`
No. Due to security issues, we cannot. HOWEVER! You can certainly use an [SSH tunnel](https://duckduckgo.com/?q=ssh+tunnnel) to access it.
**Old thunix did {fill in the blank}, and now it doesn't. Make it work like it used to!** **Old thunix did {fill in the blank}, and now it doesn't. Make it work like it used to!**
There was a huge changeover. Maybe we can get something going old thunix had, and maybe not. You can mention it in the IRC channel, and we'll see what we can do. - There was a big changeover. Some old stuff can come back, some cant.
- Mention it in **#thunix** and well see whats realistic.
**How can I access my thunix email?** **How can I access my thunix email?**
You can use the following for your mail settings (This is Thunderbird's setting screen, but the settings are the same): - Use these settings in Thunderbird, Apple Mail, Outlook, mutt, a ham radio, whatever.
[![](/media/mail.png)](/media/mail.png) ## Incoming Mail (IMAP)
- **Server:** `thunix.net`
- **Username:** `yourusername`
- **Password:** your **mail/service** password (not your SSH key)
- **Security:** SSL/TLS
- **Port:** `993`
## Outgoing Mail (SMTP)
- **Server:** `thunix.net`
- **Authentication:** Yes (same username/password as above)
- **Security:** STARTTLS
- **Port:** `587`

View File

@@ -1,27 +0,0 @@
# GDPR Statement and Privacy Policy
Thunix takes privacy seriously, and as such remains committed to being in compliance with the GDPR, which took affect on May 25th, 2018.
## What data do we collect from you?
Thunix collects your email address, during signup, and IPs you log into the system from, in accordance with technical requirements.
We also store whatever data you create or maintain in your home directory on Thunix, which may include emails to and from your Thunix account.
## How long do we retain data about you?
Your email address is retained only long enough to process you account creation request. IPs you log into from are retained for a maximum of 30 days.
## How can I request a copy of my data?
You can submit a request at [contact page](/contact). We will endeavor to provide you a copy of all data we store within 14 days.
## How can I request removal of my information?
You can submit a request at [contact page](/contact), and we will endeavor to remove all personal data of yours from our system within 14 days. However, this will include removal of your user account from our system as well, which will prevent access to most of the services provided by Thunix.
If you request deletion of your account, all of your data will be purged within 14 days from our system.
## How do you protect my data?
All data on thunix is encrypted at rest. Logs are maintained only for as long as is technically required (30 days, for troubleshooting of issues). Personally created data, is protected by the UNIX permissions model, as dictated by yourself, however, by default, your personally created data is viewable by all other users of the system, per design.

View File

@@ -5,14 +5,10 @@ We're so glad you could drop by and we hope you enjoy your visit. Stay a while!
## About thunix ## About thunix
thunix offers Secure Shell (SSH) accounts, Web Hosting, Email Accounts, and many other services. But, most of all, we are a community of users. It was founded by hexhaxtron in the Summer of 2017, and was continued by [amcclure](/~amcclure) and [ubergeek](/~ubergeek) since 2018. We aim to provide the best service possible with a wide variety of features, and we hope you have fun with it! The Thunix project provide Secure Shell (SSH) accounts, Web Hosting, Email Accounts, and many other UNIX-like services. But, most of all, we are a community of users. It was founded by hexhaxtron in the Summer of 2017, and was continued by [ubergeek](/~ubergeek) since 2018 however in 2023 [deepend](/~deepend) has since taken the role. We aim to provide the best service possible with a wide variety of features, and we hope you have fun with it!
## Project Phoenix Join us on IRC on irc.newnet.net/6697 in the #thunix channel, or just click here for a web client: [![#thunix channel](https://stats.newnet.net/badges/badge.php?channel=%23thunix)](https://newnet.net/chat.php?channel=%23thunix)
The thunix Phoenix project aims to provide a new user experience for shell users, with integration into the wider Tildeverse network.
Join us on IRC on irc.tilde.chat/6697 in the #thunix channel, or just click here for a web client: [![#thunix channel](https://tilde.chat/badges/badge.php?channel=%23thunix)](https://web.tilde.chat/?join=thunix)
If you want to sign up for an account, simply open our [signup form](/signup) and provide us with: If you want to sign up for an account, simply open our [signup form](/signup) and provide us with:

View File

@@ -1,29 +1,33 @@
# State of the Thunix - July 09, 2019 # Seasons Greetings - December 2025
Another Month! As the year winds down, a sincere thank-you to everyone whos made Thunix feel like a real community and not just “a server with accounts.” Whether youre here for SSH, web hosting, email, or the other UNIX-y odds and ends, were glad youre part of this little corner of the internet.
We are at month 7 for Thunix.net! If youre taking some quiet time over the holidays, consider doing something wonderfully low-pressure: update your `~/public_html`, publish something on Gopher, poke at the Gemini capsule (`gemini://thunix.net`), or just hang out with us on IRC (`irc.newnet.net:6697` in `#thunix`). No algorithms, no shouting, just people making things.
Newly, over the past month, we have a wiki now! It's an effort led by However you spend the season: take care of yourself, be decent to each other, and well keep doing our best to keep Thunix stable, secure, and fun.
contribute via tildegit, by opening a PR at:
https://tildegit.org/thunix/wiki # Changes to Terms of Service and Service Updates - April 2025
It's all in markdown, so it's pretty easy to contribute too. And, if you We've updated our Terms of Service to clarify rules around running servers—now explicitly prohibited without prior approval. Please take a moment to review these important changes.
mess something up? No worries! It's a wiki! We can revert :)
Also, new this month, we've made an official process and tool to provision Additionally, due to low usage and maintenance overhead, we've decided to discontinue our BZFlag, Minetest, and Minecraft servers effective immediately. We appreciate everyone who participated and hope you enjoyed your time on these services.
MySQL/MariaDB databases (It's MariaDB, btw). All you need to do is
request one, and we'll gladly add it :)
No donations this month, and costs to operate the server still sit at Thank you for your understanding and continued support!
feel the need to do so, via https://thunix.net/donate.php
Iris is getting some usage too, so make sure you poke in there, via the # Gemini is Live on Thunix! - Nov 2024
cli.
All in all, new features, new stuff, and looking forward to seeing other Hey everyone, exciting news—Thunix now supports Gemini! 🎉
contributions and new features come in from our users.
Your Friendly Neighborhood Sysadmin; You can check out our Gemini capsule at gemini://thunix.net. It's simple, fast, and perfect for sharing cool stuff without all the web bloat.
ubergeek/ub3geek
Got ideas for Gemini content? Let us know! And if youre new to Gemini, dive in—its like the web, but chill. 😎
Catch you in the capsule! 🚀
# State of the Thunix - July 2023
We are on the mend. deepend from tilde.club has taken on running Thunix and has started to build it up on his
own infrastructure. Sign ups that come in will be kept in queue until the system is ready
for more users.
More to come very soon.

25
articles/privacy.md Normal file
View File

@@ -0,0 +1,25 @@
# Privacy Policy
Thunix takes user privacy seriously.
## What data do we collect?
We collect your email address during signup and log the IP addresses used to access the system.
We also store any data you create or maintain in your home directory, which may include emails to and from your Thunix account.
## How long do we retain data?
- Email addresses: Retained for account management.
- Login IP addresses: Retained for a maximum of 30 days.
## Requesting data deletion
You may submit a deletion request via our [contact page](/contact). Account deletion will also remove all your data, typically within 14 days.
## How do we protect your data?
Data is **not encrypted at rest**. Access is controlled by standard UNIX file permissions. Users should **not store sensitive or confidential information** on Thunix.
Logs are retained only for as long as necessary for troubleshooting (30 days).
---

View File

@@ -1,31 +1,33 @@
# Service Status and Information # Service Status and Information
## Minetest
Connect to thunix.net:30000 in your minetest client
## Minecraft
Connect to thunix.net in your minecraft client. Running the Paperclip minecraft server.
## Mail Services ## Mail Services
Thunix offers webmail at [https://thunix.net/webmail](/webmail). You can also connect via imap. Thunderbird will autodetect your settings, and we recommend the use of Thunderbird email client, so you can get the best-of-breed email experience. We also recommend using enigmail with Thunderbird as well. You can get it from your distro's package manager, or from [the Thunderbird project's site](https://www.thunderbird.net/) Thunix offers webmail at [https://thunix.net/webmail](/webmail). You can also connect via imap. Thunderbird will autodetect your settings, and we recommend the use of Thunderbird email client, so you can get the best-of-breed email experience. We also recommend using enigmail with Thunderbird as well. You can get it from your distro's package manager, or from [the Thunderbird project's site](https://www.thunderbird.net/)
## SSH Fingerprints
256 SHA256:iuqEWXCqUNihqO7o4xLrJ05M+te09i3P+WrHZsjUdZY thunix.net (ECDSA)
3072 SHA256:7gZXCqNUYBfrTQ8wYmLrD6rVc5zL5nYf2l5t8ZrLIBU thunix.net (RSA)
256 SHA256:d+J8u5pmQ8sR1BM8/EpUiNAlL9by371utl1ncNgFG6A thunix.net (ED25519)
## Onion Service ## Onion Service
Thunix's services are available as a onion site as well. Our onion address is thunixme5v4rnoby.onion. Thunix's websites are available as a onion site as well. (SSH access is currently not available over Tor)
Our Tor network (The Onion Router) address is kbguajmip4jlr2k3vpscmvymtxqnft267ox2ij6pdrgb5jcvx3kctkyd.onion.
## BZFlag Game Server
BZFlag runs on the standard port. If you have a specific map you want loaded, send an email to root, and we'll look at getting the map swapped out
## IRC Chat ## IRC Chat
Thunix is part of the tilde.chat network. You can access chat via the terminal, with the 'chat' command, via your favorite email client at irc.tilde.chat/6697, or via a web chat interface located [here](). Thunix is part of the Newnet IRC network. You can access chat via the terminal, with the 'chat' command, via your favorite email client at irc.newnet.net/6697, or via a web chat interface located [![#thunix channel](https://stats.newnet.net/badges/badge.php?channel=%23thunix)](https://web.newnet.net/?join=thunix).
## FOSS Project Mirrors ## FOSS Project Mirrors
Thunix hosts mirrors for several FOSS projects. You can see the full mirror list in the sidebar link. Thunix hosts mirrors for several FOSS projects. You can see the full mirror list in the sidebar link.
## Website and CMS hosting
Collaborative creation, modification and management of digital content.
- LAMP (Apache HTTP server, MySQL database and PHP scripting language) is an open source software stack on Linux environment, available to host a variety of web sites, content management systems and applications.
- Django web development framework.
<!-- Begin autogen content from /includes/server.php --> <!-- Begin autogen content from /includes/server.php -->

View File

@@ -14,6 +14,6 @@ If you have any questions or problems, feel free to contact us.
<input type='submit'> <input type='submit'>
</form> </form>
If you don't have a public SSH key, don't worry! Check out [this guide to SSH keys](https://tilde.team/wiki/?page=ssh) and make sure that you only fill in your public SSH key here. If you don't have a public SSH key, don't worry! Check out [this guide to SSH keys](https://wiki.thunix.net/wiki/ssh) and make sure that you only fill in your public SSH key here.
Signing up implies that you agree with our [terms of service](/tos). If you haven't done so, please read it before you sign up. Signing up implies that you agree with our [terms of service](/tos). If you haven't done so, please read it before you sign up.

View File

@@ -1,3 +1,3 @@
# Success! # Form Failure
You will hear back shortly from us! You didn't properly fill out the signup form. Please try again.

3
articles/success3.md Normal file
View File

@@ -0,0 +1,3 @@
# Form Failure
This username is already registered, please choose another one.

3
articles/success4.md Normal file
View File

@@ -0,0 +1,3 @@
# Form Failure
Please check SSH public key format.

View File

@@ -2,36 +2,39 @@
Nothing is without its rules and regulations; thunix is no exception. Nothing is without its rules and regulations; thunix is no exception.
Below are the site's service terms. Everything in this page should be clear to everyone who wishes to use thunix's services; failure to abide by these terms can result in penalties such as service bans and may result in legal action against any offending users, depending on the severity of each case and any other individuals who may have been affected. Thunix may conduct investigations on any suspected violations, and we will cooperate with law enforcement agencies with their investigations. Be sure to read this page carefully and understand it. Below are the site's service terms. All points listed should be clear to anyone wishing to use thunix's services. Failure to abide by these terms can result in penalties, including service bans and potential legal action, depending on the severity of the violation. Thunix may investigate suspected violations and will cooperate fully with law enforcement agencies as necessary. Read and understand these terms carefully.
You are responsibe for checking your local mail account from time to You are responsible for regularly checking your local mail account. This email address is our primary means of communication, and any warnings or notices regarding your account or service status will be sent there.
time. This email address is the only one we retain, and as such, any
warnings and notices regarding your account, or service status will be
sent to this account.
1. Deliberately defacing the accounts of other users Prohibited activities include, but are not limited to:
2. Deliberately trying to disrupt thunix's server
3. Using thunix as a launch pad for disrupting other servers
4. Using thunix to impersonate other websites and businesses for
criminal purposes
5. Storing/distributing pornography of any genre and medium (especially
child pornography)
6. Storing/distributing content that defames any individual
7. Promoting racial, ethnic, religious, political and other forms of
bigotry
8. Storing/distributing, promoting, or encouraging use of
pirated/cracked software, license keys, license/registration
circumvention programs, or any questionable programs/scripts that
can risk causing unauthorized modifications, or disrupts network
services for any programs or devices.
9. Mining cryptocurrencies
10. Spamming on any forums, mailing lists, irc channels,
newsgroups, etc.
11. Leaking or publishing any user's or individual's personal
information without that person's consent.
Copyright infringement is not allowed on thunix, and we will not allow any illegal content to be distributed. It's also expected that all users respect the copyrights of those who produce original content of any kind and only share if the author or license grants you permission. Content hosted on accounts used for external file storage must also follow copyright law. 1. Deliberately defacing or tampering with other users' accounts.
2. Intentionally disrupting or attempting to disrupt thunix's servers.
3. Using thunix as a platform to attack or disrupt other servers or services.
4. Using thunix to impersonate websites, individuals, or businesses for malicious or criminal purposes.
5. Hosting or distributing pornography of any type or medium, especially child pornography.
6. Storing, distributing, or promoting content that defames or slanders any individual or entity.
7. Promoting racial, ethnic, religious, political, or other forms of bigotry or hate speech.
8. Storing, distributing, promoting, or encouraging the use of pirated or cracked software, unauthorized license keys, or any software or scripts intended to bypass security or disrupt network services.
9. Mining cryptocurrencies.
10. Sending spam or unsolicited messages through forums, mailing lists, IRC channels, newsgroups, or other communication channels.
11. Leaking, publishing, or distributing personal or sensitive information about any individual without explicit consent.
12. Using thunix services for any activities you believe or suspect might be illegal.
13. Using thunix services for commercial purposes or profit-making activities.
14. Running servers or network services (such as web, mail, game, file-sharing, VPN, or proxy servers) without explicit permission.
15. Reselling or subletting access to thunix services under any circumstances.
16. Allowing or contributing to frequent attacks or disruptions targeting your account or hosted content. If such activities occur regularly, we reserve the right to disable or remove your service.
If you want to request for content you own the copyright for to be removed from thunix, please refer to our [abuse reporting page](/contact). In the email, please identify who you are, if you are the copyright holder or legally representing them, the exact files you want removed with links to the files and infringed content, and contact information such as phone numbers or a reply-to email address. ### Additional Conditions:
- Thunix backs up your data on a best-effort basis, but users are responsible for maintaining their own regular backups.
- Support provided by thunix is volunteer-based; mutual respect and patience are expected at all times.
Copyright infringement and distribution of illegal content are strictly prohibited. Users must respect copyright laws and obtain explicit permission from content owners or valid license holders before sharing any material. Content hosted for external storage purposes must also comply with all relevant copyright laws.
To request the removal of copyrighted material you own from thunix, please use our [abuse reporting page](/contact). Clearly identify your relationship to the copyrighted content, specify the exact files or links involved, and provide detailed contact information, including a reply-to email address or phone number.
Repeated or severe violations of these Terms of Service may result in immediate account removal. These terms apply to all communication platforms hosted by or associated with thunix, including forums, mailing lists, IRC channels, newsgroups, and similar services.
If you notice any violations, please report them through our [abuse reporting page](/contact).
Users that repeatedly violate the Terms of Service will have their account removed. Depending on the degree of the offense, their account may be removed immediately. These terms also apply to communication services such as forums, mailing lists, irc channels, newsgroups, and any other service either hosted on or used for thunix. If you come across anything that violates the terms of service, please let us know with the [abuse reporting page](/contact).

View File

@@ -1,14 +1,13 @@
<?php <?php
//Name of your site //Name of your site
$site_name=" thunix "; $site_name="🌻 thunix 🌻";
//Root for the site, in a browser //Root for the site, in a browser
//$site_root="https://dev.thunix.cf"; $site_root="//".$_SERVER['HTTP_HOST'];
$site_root="https://".$_SERVER['HTTP_HOST'];
//Local base root for app files //Local base root for app files
$doc_root="/var/www/dev.thunix.cf"; $doc_root="/var/www/thunix.cf";
//Site style //Site style
// site is the default. Specify something else here to switch // site is the default. Specify something else here to switch
$site_style="thunix"; $site_style="newthunix";
?> ?>

46
gen_tdp
View File

@@ -1,46 +0,0 @@
#!/usr/bin/env python3
import subprocess,json,os.path,requests
from bs4 import BeautifulSoup as bs
headers = {
'Accept-Encoding': 'gzip, deflate, sdch',
'Accept-Language': 'en-US,en;q=0.8',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
}
tdp = {}
tdp["name"] = "thunix"
tdp["url"] = "https://www.thunix.net"
tdp["signup_url"] = tdp["url"]+"/signup.php"
users = subprocess.check_output(["/usr/bin/members","tilde"]).decode('ascii').split()
users.sort()
tdp["user_count"] = len(users)-1
tdp["want_users"] = True
tdp["admin_email"] = "root@thunix.net"
tdp["description"] = "Thunix is a community, centered around access to a public *nix system. Thunix offers shell accounts with complete set of programming tools, and follows a continuous integration-continuous deployment of system configuration."
tdpusers = []
for user in users:
if user=="anton":
continue
tdpuser = dict(username=user)
title = bs(requests.get("https://www.thunix.net/~{}".format(user)).text,"lxml").title
if title is None:
title = "No title"
else:
title = title.text
tdpuser["title"] = title
if os.path.exists(os.path.expanduser("~{}/public_html/index.html".format(user))):
tdpuser["mtime"] = os.path.getmtime(os.path.expanduser("~{}/public_html/index.html".format(user)))
elif os.path.exists(os.path.expanduser("~{}/public_html/index.htm".format(user))):
tdpuser["mtime"] = os.path.getmtime(os.path.expanduser("~{}/public_html/index.htm".format(user)))
elif os.path.exists(os.path.expanduser("~{}/public_html/index.php".format(user))):
tdpuser["mtime"] = os.path.getmtime(os.path.expanduser("~{}/public_html/index.php".format(user)))
tdpusers.append(tdpuser)
tdp["users"] = tdpusers
with open("tilde.json","w") as f:
json.dump(tdp,f)

View File

@@ -16,8 +16,6 @@
/* security */ /* security */
$access_token = "secret"; $access_token = "secret";
$ansible_lastrun = '/dev/shm/ansible-hook-last-run';
$ansible_dropfile = '/dev/shm/run-ansible';
$www_lastrun = '/dev/shm/www-hook-last-run'; $www_lastrun = '/dev/shm/www-hook-last-run';
$www_dropfile = '/dev/shm/run-www'; $www_dropfile = '/dev/shm/run-www';
$gopher_lastrun = '/dev/shm/gopher-hook-last-run'; $gopher_lastrun = '/dev/shm/gopher-hook-last-run';
@@ -25,7 +23,7 @@ $gopher_dropfile = '/dev/shm/run-gopher';
$wiki_lastrun = '/dev/shm/wiki-hook-last-run'; $wiki_lastrun = '/dev/shm/wiki-hook-last-run';
$wiki_dropfile = '/dev/shm/run-wiki'; $wiki_dropfile = '/dev/shm/run-wiki';
$allowedip = '51.79.32.48'; $allowedip = '198.50.210.248';
$remoteip = $_SERVER['REMOTE_ADDR']; $remoteip = $_SERVER['REMOTE_ADDR'];
$ratelimit = 300; $ratelimit = 300;
@@ -51,24 +49,6 @@ if ( strcmp($remoteip, $allowedip) !== 0 )
exit(0); exit(0);
} }
// Hook for ansible here
if ($data["repository"]["full_name"] == 'thunix/ansible') {
syslog(LOG_INFO, 'Ansible Webhook recieved.');
// We limit runs to once per 5 minutes, so they don't try
// overlapping. Systemd shouldn't allow it, but we'll check
// anyways
if ( time () - filemtime ( $ansible_lastrun ) > $ratelimit ) {
touch ( $ansible_dropfile );
touch ( $ansible_lastrun );
echo "HTTP 200 - Ansible webhook recieved.\n";
}
else {
http_response_code(429);
echo "HTTP 429 - Rate Limited.\n";
exit(0);
}
}
// Hook for www repo here. Same rules apply, as above, for www. We // Hook for www repo here. Same rules apply, as above, for www. We
// could probably make it able to run more frequently. Backend job is // could probably make it able to run more frequently. Backend job is
// just a git pull, and is quick. // just a git pull, and is quick.
@@ -119,8 +99,8 @@ elseif ($data["repository"]["full_name"] == 'thunix/wiki') {
} }
} }
// Easter egg for anyone probing the hook. Enjoy. We're a coffee maker // Easter egg for anyone probing the hook. Enjoy. We're a tea pot
// and not a teapot :) // and not a coffee maker :)
else { else {
http_response_code(418); http_response_code(418);
echo "HTTP 418 - I'm a teapot.\n"; echo "HTTP 418 - I'm a teapot.\n";
@@ -128,22 +108,5 @@ else {
exit(0); exit(0);
} }
/*$fp = pfsockopen( "tcp://127.0.0.1", 1234, $errno, $errstr );
if (!$fp)
{
echo "ERROR: $errno - $errstr<br />\n";
}
socket_set_timeout ($fp, 10);
$msg = "Commit '".$data['commits'][0]["message"]."' was pushed to ".$data["repository"]["full_name"].' by '.$data["pusher"]["login"];
$msg = trim(preg_replace('/\s+/', ' ', $msg));
$write = fwrite ($fp, $msg);
fclose($fp);
if (!$write) {
echo "error writing to port.<br/>";
next;
}
*/
?> ?>

View File

@@ -1,16 +1,16 @@
/* TEAM */ /* TEAM */
Your title: ubergeek, naglfar, amcclure, fosslinux Your title: deepend, naglfar
Site: https://thunix.net, root@thunix.net Site: https://thunix.net, root@thunix.net
Location: Frankfurt, Germany Location: Quebec, Canada
/* THANKS */ /* THANKS */
Name: ubergeek https://thunix.net/~ubergeek Name: deepend https://thunix.net/~deepend
amcclure https://thunix.net/~amcclure ubergeek https://thunix.net/~ubergeek
naglfar https://thunix.net/~naglfar naglfar https://thunix.net/~naglfar
fosslinux https://thunix.net/~fosslinux fosslinux https://thunix.net/~fosslinux
/* SITE */ /* SITE */
Last update: 2019/03/22 Last update: 2023/12/26
Standards: HTML5 Standards: HTML5
Components: Apache2, Git, and PHP, Parsedown, Parsedown Extra Components: Apache2, Git, and PHP, Parsedown, Parsedown Extra
Software: vim, geany, ansible, wiki.php Software: vim, geany, ansible, wiki.php

Binary file not shown.

Before

Width:  |  Height:  |  Size: 650 KiB

View File

@@ -2,8 +2,14 @@
include "../config.php"; include "../config.php";
// This code is licensed under the AGPL 3 or later by ubergeek (https://tildegit.org/ubergeek) // This code is licensed under the AGPL 3 or later by ubergeek (https://tildegit.org/ubergeek)
// Optional: keep the terminal UI flow inside /terminal/ without changing the classic site.
//
// Prefer an explicit flag (terminal=1). As a fallback, detect a terminal embed
// by referrer so the classic site behavior stays unchanged.
$terminalMode = (isset($_REQUEST['terminal']) && (string) $_REQUEST['terminal'] === '1')
|| (isset($_SERVER['HTTP_REFERER']) && strpos((string) $_SERVER['HTTP_REFERER'], '/terminal/') !== false);
$name = $_GET['contact_name']; $name = $_GET['contact_name'];
$email = $_GET['email_address']; $return_addr = $_GET['email_address'];
$type = $_GET['type']; $type = $_GET['type'];
$body = $_GET['message']; $body = $_GET['message'];
@@ -14,22 +20,27 @@ $subject = "Contact Form";
$mailbody = "The following submission via the contact form was recieved: $mailbody = "The following submission via the contact form was recieved:
Real Name: $name Real Name: $name
Email Address: $email
Type: $type Type: $type
Message: $body"; Message: $body";
if ( $tv != "tildeverse" ) { if ( $tv != "tildeverse" ) {
print "Spam attempt"; print "Spam attempt";
header("Location: $site_root/?page=success1"); $redirect = $terminalMode
? $site_root . "/terminal/view.php?page=success1"
: $site_root . "/?page=success1";
header("Location: $redirect");
die(); die();
} }
shell_exec("echo '$mailbody' | /usr/bin/mail -s '$subject' $destination_addr "); shell_exec("echo '$mailbody' | /usr/bin/mail -s '$subject' -r '$return_addr' $destination_addr ");
// In the future, here, we *should* be able to build a process that // In the future, here, we *should* be able to build a process that
// auto opens an issue in the tildegit project // auto opens an issue in the tildegit project
header("Location: $site_root/?page=success2"); $redirect = $terminalMode
? $site_root . "/terminal/view.php?page=success2"
: $site_root . "/?page=success2";
header("Location: $redirect");
die() die()
?> ?>

BIN
includes/dot.ttf Executable file

Binary file not shown.

View File

@@ -1,6 +1,4 @@
Unless otherwise noted, all thunix.net materials (besides all user-generated content) is licensed as [CC BY-SA 4.0license](https://creativecommons.org/licenses/by-sa/4.0/). Permissions beyond the scope of this license may be available [here](/copyright). All content is licensed as [CC BY-SA 4.0 license](https://creativecommons.org/licenses/by-sa/4.0/). Users define their own licensing and own all of their content.
Users define their own licensing and own all of their content.
All questions, comments, and concerns about this site should be sent to [the administration team](/contact). All questions, comments, and concerns about this site should be sent to [the administration team](/contact).

View File

@@ -1 +1 @@
![ thunix](/media/gotthunix.png) ![🌻 thunix🌻](/media/thunix.gif)

147
includes/newthunix.css Normal file
View File

@@ -0,0 +1,147 @@
@font-face { font-family: dot; src: url('https://thunix.net/includes/dot.ttf'); }
body {
font-family: "dot", Courier, monospace;
background: #000;
color: #F79862;
}
#body {
width: 95%;
}
#body h1, #body h2, #body h3 {
color: orange;
}
a {
background: #000;
color: #F79862;
}
a:visited {
color: orange;
}
#header {
width: 90%;
text-align: center;
font-size: xx-large;
}
#content {
width: 78%;
float: left;
font-size: medium;
}
#content img {
max-height: 400px;
max-width: 98%;
}
.lineitem {
border: 1px;
border-color: #fff;
}
#sidebar {
width: 18%;
float: right;
font-size: small;
padding: 15px; /* Increase padding for more internal spacing */
margin-top: 20px; /* Add more space between the sidebar and elements above it */
margin-left: 10px; /* Add space between the sidebar and content */
background-color: #111; /* Ensure the sidebar stands out slightly */
line-height: 1.5; /* Increase line height for better readability */
border: 1px solid #333; /* Optional: Add a subtle border to separate the sidebar visually */
}
#sidebar h1, #sidebar h2 {
color: orange;
/* background: #000; */
margin-bottom: 15px; /* Further space below headings */
padding-bottom: 5px; /* Add padding under headings for better distinction */
border-bottom: 1px solid #333; /* Optional: Add an underline effect for headings */
}
#sidebar ul, #sidebar p {
margin: 10px 0; /* Add vertical spacing between sidebar elements */
padding-left: 20px; /* Indent list items for better clarity */
}
#footer {
width: 95%;
text-align: center;
clear: both;
font-size: smaller;
}
#new
/* 1) Keep terminal feel, but make reading humane */
body {
background: #050505; /* not pure black */
color: #f1a67a; /* slightly softer than #F79862 */
font-size: 16px; /* consistent baseline */
line-height: 1.65; /* biggest readability win */
text-rendering: optimizeLegibility;
}
/* 2) Use the dot font for headings/branding, but not for paragraphs */
#header,
#body h1, #body h2, #body h3 {
font-family: "dot", Courier, monospace;
letter-spacing: 0.5px;
}
#content,
#sidebar,
#footer {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
/* still terminal, but readable */
}
/* 3) Limit line length so the eyes don't have to travel across Alberta */
#content {
max-width: 980px;
font-size: 1rem;
}
/* 4) Make links look like links, not “random orange words” */
a {
color: #f1a67a;
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 3px;
}
a:hover {
color: #ffb58f;
}
a:visited {
color: #e6a042; /* still orange, but distinct */
}
/* 5) Softer headings and better spacing */
#body h1, #body h2, #body h3,
#sidebar h1, #sidebar h2 {
color: #ffb347; /* softer orange */
margin-top: 1.2em;
margin-bottom: 0.6em;
}
/* 6) Sidebar: keep the panel look, make it calmer */
#sidebar {
background-color: #0c0c0c; /* slightly lighter */
border: 1px solid #222;
border-radius: 6px; /* tiny, still “retro UI” */
}
/* 7) Fix your lineitem border (currently border:1px does nothing) */
.lineitem {
border: 1px solid #222;
}
/* 8) Optional: code blocks that actually read nicely */
pre, code {
background: #0b0b0b;
border: 1px solid #1f1f1f;
border-radius: 6px;
padding: 0.15em 0.35em;
}
pre {
padding: 12px;
overflow-x: auto;
}

View File

@@ -1,77 +1,9 @@
<?php <?php
/*
This code is licensed under the AGPL 3 or later by ubergeek (https://tildegit.org/ubergeek)
Parsedown is licensed under the MIT license.
*/
include('../config.php');
include('../parsedown-1.7.3/Parsedown.php');
include('../parsedown-extra-0.7.1/ParsedownExtra.php');
$page = $_GET['page'];
$style = $_GET['style'];
$Parsedown = new Parsedown();
$Parsedown->setMarkupEscaped(true);
$ParsedownExtra = new ParsedownExtra();
if ( $page == "") {
$page = "main";
}
if ( $style == "") {
if ( $site_style == "") {
$site_style="site";
}
}
else {
$site_style=$style;
}
$header = file_get_contents("$doc_root/includes/header.md");
$sidebar = file_get_contents("$doc_root/includes/sidebar.md");
$content = file_get_contents("$doc_root/articles/server.md");
$footer = file_get_contents("$doc_root/includes/footer.md");
print "<!DOCTYPE html>
<html lang='en'>
<head>
<title>$site_name - $page</title>
<link rel='stylesheet' type='text/css' href='$site_root/includes/$site_style.css'>
</head>
<body>
<!-- Begin Header -->
<div id='header'>";
print $Parsedown->text($header);
print "
</div>
<!-- End Header -->
";
print "<hr>
<div id='body'>
<!-- Begin Sidebar -->
<div id='sidebar'>
";
echo $Parsedown->text($sidebar);
print " </div>
<!-- End Sidebar -->
<!-- Begin Body -->
<div id='content'>";
echo $ParsedownExtra->text($content);
// Monitoring section // Monitoring section
$hosts="all"; $hosts="all";
$f = fopen("./report", "r"); $f = fopen("$doc_root/report", "r");
echo "Last update: " . date ("H:i", filemtime('./report'))."<p>\n"; echo "Last update: " . date ("H:i", filemtime('./report'))."<p>\n";
echo "<table style='width:80%'>"; echo "<table style='width:80%'>";
@@ -113,21 +45,4 @@ echo "\n</table>\n";
fclose($f); fclose($f);
// End monitoring section // End monitoring section
print " </div>
<!-- End Body -->
</div>
<!-- Begin Footer -->
<div id='footer'>
<hr>
";
echo $Parsedown->text($footer);
print " </div>
<!-- End Footer -->
</body>
</html>";
?> ?>

View File

@@ -1,29 +1,29 @@
- Main Menu - Main Menu
--------- ---------
- [Home](/main) - [Home](/main)
- [Sign Up](/signup)
- [FAQ](/faq) - [FAQ](/faq)
- [Terms of Service](/tos) - [Terms of Service](/tos)
- [GDPR Statement and Privacy Policy](/gdpr) - [Privacy Policy](/privacy)
- [Contact Us](/contact) - [Contact Us](/contact)
- [Sign Up](/signup) - [Donations](https://donate.tilde.club)
- [thunix Mirror Services](https://ftp.thunix.net/)
- [Web Server Stats](https://stats.thunix.net/)
- [Donations](/donate)
- Main Resources On This Site
---------------------------
- Resources and User Content
---------------------------
- [Wiki](https://wiki.thunix.net/) - [Wiki](https://wiki.thunix.net/)
- [Status of thunix Servers and Services](/server)
- [Service News](/news)
- [User Web Directories](/users) - [User Web Directories](/users)
- [User Gopher Directories](https://gopher.tildeverse.org/thunix.net) - [User Gopher Directories](https://gopher.tildeverse.org/thunix.net)
- [Web Mail](/webmail/) - [User Gemini Directories](https://gemini.tildeverse.org/?gemini://thunix.net/)
- [ZNC Service](https://thunix.net:1326/)
- Server Staff
------------
- [Anton McClure](/~amcclure/) - Services and Status
- [Ubergeek](/~ubergeek/) --------------------
- [Status and Information](/server)
- [Service News](/news)
- [Web Server Stats](https://stats.thunix.net/)
- [Web Mail](/webmail/)
- [ZNC Service](https://thunix.net:1356/)
- Server Staff
-------------
- [deepend](/~deepend/)
- [Naglfar](/~naglfar/) - [Naglfar](/~naglfar/)
- [fosslinux](/~fosslinux/)

View File

@@ -1,7 +1,12 @@
<?php <?php
// This code is licensed under the AGPL 3 or later by ubergeek (https://tildegit.org/ubergeek)
include "../config.php"; include "../config.php";
// Optional: keep the terminal UI flow inside /terminal/ without changing the classic site.
//
// Prefer an explicit flag (terminal=1). As a fallback, detect a terminal embed
// by referrer so the classic site behavior stays unchanged.
$terminalMode = (isset($_REQUEST['terminal']) && (string) $_REQUEST['terminal'] === '1')
|| (isset($_SERVER['HTTP_REFERER']) && strpos((string) $_SERVER['HTTP_REFERER'], '/terminal/') !== false);
$name = $_GET['contact_name']; $name = $_GET['contact_name'];
$email = $_GET['email_address']; $email = $_GET['email_address'];
$username = $_GET['username']; $username = $_GET['username'];
@@ -9,8 +14,12 @@ $interest = $_GET['interest'];
$pubkey = $_GET['pubkey']; $pubkey = $_GET['pubkey'];
$tv = $_GET['tv']; $tv = $_GET['tv'];
$destination_addr = "newuser@thunix.net"; $username = strtolower($username);
$subject = "New User Registration"; $pubkey = trim($pubkey);
$from = 'From: www-data <www-data@thunix.net>';
$destination_addr = 'newuser@thunix.net';
$subject = 'New User Registration';
$mailbody = "A new user has tried to register. $mailbody = "A new user has tried to register.
Username: $username Username: $username
Real Name: $name Real Name: $name
@@ -18,19 +27,33 @@ Email Address: $email
Interest: $interest Interest: $interest
Pubkey: $pubkey"; Pubkey: $pubkey";
if ( $tv != "tildeverse" ) { $user_queue = '/dev/shm/userqueue';
print "Spam attempt";
header("Location: $site_root/?page=success1"); $success = 'success1';
die(); if ($tv == 'tildeverse') {
$success = 'success2';
if (posix_getpwnam($username)) {
$success = 'success3';
}
$valid_key_starts = ['ssh-rsa', 'ssh-dss', 'ecdsa-sha2', 'ssh-ed25519'];
$key_parts = explode(' ', $pubkey, 3);
if (!in_array($key_parts[0], $valid_key_starts) || count($key_parts) < 2) {
$success = 'success4';
}
if ($success === 'success2') {
mail($destination_addr, $subject, $mailbody, $from);
$fp = fopen($user_queue, 'a');
fwrite($fp, "'$username','$email','$pubkey'\n");
fclose($fp);
$fp2 = fopen('/var/signups', 'a');
fwrite($fp2, 'makeuser ' . $username . ' ' . $email . ' "' . addslashes($pubkey) . "\"\n");
fclose($fp2);
}
} }
shell_exec("echo '$mailbody' | /usr/bin/mail -s '$subject' $destination_addr "); if ($terminalMode) {
header("Location: $site_root/terminal/view.php?page=$success");
// In the future, here, we *should* be able to build a process that } else {
// somehow auto-verifies the user, and instead of email, it'll kick off the new user process here header("Location: $site_root/?page=$success");
}
header("Location: $site_root/?page=success2");
die(); die();
?>

265
includes/terminal.css Normal file
View File

@@ -0,0 +1,265 @@
/*
Terminal theme for /terminal/view.php.
Keeps the same wiki.php content pipeline (Parsedown/ParsedownExtra),
but makes it look like the amber CRT terminal UI.
This file is loaded inside an <iframe> (terminal content panel), so it must
style full documents reliably without depending on any outer page CSS.
*/
:root {
color-scheme: dark;
/* Keep these in sync with terminal/index.php. */
--mono: "Departure Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
"Liberation Mono", "Courier New", monospace;
--bg: #111111;
--panel: rgba(255, 255, 255, 0.03);
--amber: #edb200;
--amber-txt: #ffc828;
--border: rgba(255, 255, 255, 0.08);
--glow: rgba(237, 178, 0, 0.55);
--glow-soft: rgba(237, 178, 0, 0.25);
}
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
body {
background: var(--bg);
color: var(--amber);
font-family: var(--mono);
font-size: 18px; /* Match xterm.js default in terminal.js */
line-height: 1.55;
overflow-x: hidden;
}
/* CRT-ish scanlines, because humans love pretending its 1996. */
body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
z-index: 2;
background: linear-gradient(to bottom, transparent 50%, rgba(0, 0, 0, 0.28) 51%);
background-size: 100% 4px;
}
/* Keep content above page background but below scanlines. */
#content {
position: relative;
z-index: 1;
width: 100%;
padding: 18px 20px;
background: transparent;
}
/* Hide classic wiki chrome if a fragment includes it for any reason. */
#header,
#sidebar,
#footer {
display: none;
}
/* Typographic polish */
h1,
h2,
h3 {
margin: 0.9em 0 0.35em;
line-height: 1.15;
color: var(--amber-txt);
text-shadow: 0 0 1.4rem var(--glow-soft);
}
h1 {
font-size: 1.55rem;
}
h2 {
font-size: 1.25rem;
}
h3 {
font-size: 1.1rem;
}
p {
margin: 0.75em 0;
}
strong {
color: var(--amber-txt);
}
hr {
border: 0;
border-top: 1px solid var(--border);
margin: 14px 0;
}
/* Keep images sane inside the panel. */
img {
max-width: 100%;
height: auto;
}
/* Lists */
ul,
ol {
margin: 0.65em 0 0.9em 1.25em;
padding: 0;
}
li {
margin: 0.2em 0;
}
/* Links */
a,
a:visited {
color: var(--amber-txt);
text-decoration: underline;
text-decoration-thickness: 2px;
text-underline-offset: 3px;
text-shadow: 0 0 0.85rem rgba(237, 178, 0, 0.3);
}
a:hover {
filter: brightness(1.08);
text-shadow: 0 0 1.25rem rgba(237, 178, 0, 0.55);
}
/* Code */
code,
pre {
font-family: var(--mono);
}
code {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.06);
padding: 0.08em 0.3em;
border-radius: 6px;
}
pre {
padding: 12px;
background: var(--panel);
border: 1px solid var(--border);
border-radius: 6px;
overflow: auto;
line-height: 1.45;
}
pre code {
background: transparent;
border: 0;
padding: 0;
}
/* Tables (contact/signup forms, lists). */
table {
border-collapse: collapse;
width: 100%;
max-width: 980px;
}
th,
td {
padding: 8px 10px;
vertical-align: top;
}
tr + tr td,
tr + tr th {
border-top: 1px solid rgba(255, 255, 255, 0.06);
}
/* Form controls should look like they belong here. */
input,
select,
textarea {
width: 100%;
max-width: 100%;
background: var(--panel);
color: var(--amber);
border: 1px solid var(--border);
border-radius: 6px;
padding: 8px 10px;
font-family: var(--mono);
font-size: 18px;
outline: none;
}
textarea {
resize: vertical;
}
input:focus,
select:focus,
textarea:focus {
border-color: rgba(255, 200, 40, 0.55);
box-shadow: 0 0 0 2px rgba(255, 200, 40, 0.15);
}
input[type='submit'],
button {
width: auto;
cursor: pointer;
background: rgba(255, 200, 40, 0.14);
border-color: rgba(255, 200, 40, 0.32);
padding: 10px 14px;
}
input[type='submit']:hover,
button:hover {
filter: brightness(1.1);
}
/* Blockquotes */
blockquote {
margin: 1em 0;
padding: 0.2em 0.9em;
border-left: 3px solid rgba(255, 200, 40, 0.28);
background: rgba(255, 255, 255, 0.02);
}
/* Selection */
::selection {
background: rgba(255, 200, 40, 0.22);
color: var(--amber-txt);
}
/* Scrollbars (best-effort, doesnt break anything if unsupported). */
html {
scrollbar-color: rgba(255, 200, 40, 0.55) rgba(0, 0, 0, 0.2);
scrollbar-width: thin;
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.22);
}
::-webkit-scrollbar-thumb {
background: rgba(255, 200, 40, 0.35);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 200, 40, 0.5);
}

View File

@@ -1,98 +1,26 @@
<?php <?php
/* $html_skel = '/etc/skel/public_html/index.html';
This code is licensed under the AGPL 3 or later by ubergeek (https://tildegit.org/ubergeek)
Parsedown and Parsedown Extra is licensed under the MIT license.
*/
include('../config.php');
include('../parsedown-1.7.3/Parsedown.php');
include('../parsedown-extra-0.7.1/ParsedownExtra.php');
$page = $_GET['page'];
$style = $_GET['style'];
$Parsedown = new Parsedown();
$Parsedown->setMarkupEscaped(true);
$ParsedownExtra = new ParsedownExtra();
if ( $page == "") {
$page = "main";
}
if ( $style == "") {
if ( $site_style == "") {
$site_style="site";
}
}
else {
$site_style=$style;
}
$header = file_get_contents("$doc_root/includes/header.md");
$sidebar = file_get_contents("$doc_root/includes/sidebar.md");
$content = file_get_contents("$doc_root/articles/userdir.md");
$footer = file_get_contents("$doc_root/includes/footer.md");
print "<!DOCTYPE html>
<html lang='en'>
<head>
<title>$site_name - $page</title>
<link rel='stylesheet' type='text/css' href='$site_root/includes/$site_style.css'>
</head>
<body>
<!-- Begin Header -->
<div id='header'>";
print $Parsedown->text($header);
print "
</div>
<!-- End Header -->
";
print "<hr>
<div id='body'>
<!-- Begin Sidebar -->
<div id='sidebar'>
";
echo $Parsedown->text($sidebar);
print " </div>
<!-- End Sidebar -->
<!-- Begin Body -->
<div id='content'>";
echo $ParsedownExtra->text($content);
print "<!-- Begin autogen userdir list -->"; print "<!-- Begin autogen userdir list -->";
print "<ul style='list-style: none; margin-left: -40px;'>"; print "<ul style='list-style: none; margin-left: -40px;'>";
foreach (glob("/home/*") as $user):
if (!is_dir($user . "/public_html") || (!file_exists($user . "/public_html/index.html") && !file_exists($user . "/public_html/index.php")))
continue;
$user = basename($user);
print"<li><a href='$site_root/~$user/'>~$user</a></li>";
endforeach;
print "</ul></div>
<!-- End Autgen userdir list -->";
print " </div> foreach (glob("/home/*") as $userpath) {
<!-- End Body --> if (is_dir("$userpath/public_html")) {
$user = basename($userpath);
</div> // Use @ to suppress warnings in case the user directory/files are not readable.
$skeletonMatch = (@sha1_file($html_skel) === @sha1_file("$userpath/public_html/index.html"));
$isEmptyPubhtml = (@count(@scandir("$userpath/public_html")) === 2); // 2 => "." and ".."
<!-- Begin Footer --> if ($skeletonMatch || $isEmptyPubhtml) {
<div id='footer'> // If it matches the skeleton index.html or is empty, display without a link
<hr> print "<li>~$user</li>\n";
"; } else {
// Otherwise, link to the user's directory
print "<li><a href='$site_root/~$user/'>~$user</a></li>\n";
}
}
}
echo $Parsedown->text($footer); print "</ul></div>\n<!-- End Autgen userdir list -->";
print " </div>
<!-- End Footer -->
</body>
</html>";
?> ?>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 650 KiB

After

Width:  |  Height:  |  Size: 447 KiB

BIN
media/thunix.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
media/thunix.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

427
sitemap.xml Normal file
View File

@@ -0,0 +1,427 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<!-- created with Free Online Sitemap Generator www.xml-sitemaps.com -->
<url>
<loc>https://www.thunix.net/</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>1.00</priority>
</url>
<url>
<loc>https://www.thunix.net/main</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/faq</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/tos</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/gdpr</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/contact</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/signup</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/donate</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/server</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/news</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/users</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/~amcclure/</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/~ubergeek/</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/~naglfar/</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/~fosslinux/</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/copyright</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://www.thunix.net/~adam/</loc>
<lastmod>2019-06-10T13:48:44+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~aniruddh/</loc>
<lastmod>2019-04-24T17:25:18+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~brendantcc/</loc>
<lastmod>2019-02-17T23:13:11+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~cyphyx/</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~diabla/</loc>
<lastmod>2019-01-10T23:22:46+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~gokce/</loc>
<lastmod>2019-01-07T22:00:54+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~isaac/</loc>
<lastmod>2019-07-09T01:02:26+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~khuxkm/</loc>
<lastmod>2019-06-14T13:18:42+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~mandlebroth/</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~ml/</loc>
<lastmod>2019-01-23T10:05:23+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~orliesaurus/</loc>
<lastmod>2019-01-07T02:00:52+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~quetzalcoatl/</loc>
<lastmod>2019-01-21T23:53:53+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~ringo/</loc>
<lastmod>2019-01-03T01:11:03+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~sancho/</loc>
<lastmod>2019-06-01T22:07:12+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~smtpsupplicant/</loc>
<lastmod>2019-05-18T18:47:11+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~techemporium/</loc>
<lastmod>2019-06-15T23:44:56+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~thekingofbandit/</loc>
<lastmod>2019-05-29T04:46:22+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~usernameak/</loc>
<lastmod>2019-01-15T22:17:49+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~amcclure/home</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~amcclure/contact</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~amcclure/documents</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~amcclure/projects</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~amcclure/links</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~amcclure/readme</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~amcclure/license</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~amcclure/tos</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~amcclure/privacy</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~amcclure/etiquette</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~ubergeek/main</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~ubergeek/gopher</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~ubergeek/workstation</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~ubergeek/cli</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~ubergeek/thunix</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~ubergeek/sitecode</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~fosslinux/?C=N;O=D</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~fosslinux/?C=M;O=A</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~fosslinux/?C=S;O=A</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~fosslinux/?C=D;O=A</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~fosslinux/glowing-bear/</loc>
<lastmod>2019-02-08T00:38:04+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~fosslinux/proxy.php</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.64</priority>
</url>
<url>
<loc>https://www.thunix.net/~adam/copyright.html</loc>
<lastmod>2019-06-10T13:44:58+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~brendantcc/.</loc>
<lastmod>2019-02-17T23:13:11+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/en</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/en/archive</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~ml/lynx_bookmarks.html</loc>
<lastmod>2019-07-15T11:48:29+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~ml/fwa.txt</loc>
<lastmod>2019-07-16T15:57:08+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~ml/tt.txt</loc>
<lastmod>2019-01-21T07:45:06+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~ml/lw</loc>
<lastmod>2019-07-15T11:48:29+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~sancho/.</loc>
<lastmod>2019-06-01T22:07:12+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~sancho/pages/about-me.html</loc>
<lastmod>2019-06-01T22:07:12+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~sancho/category/general.html</loc>
<lastmod>2019-06-01T22:07:12+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~sancho/first-post.html</loc>
<lastmod>2019-06-01T22:07:12+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/copyright.htm</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~techemporium/htpwdgen.php</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~techemporium/crapforum.php</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~techemporium/hcsfs.php</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~techemporium/pmcms.php</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~techemporium/sshacs.php</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~techemporium/warlord.php</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~techemporium/technes.php</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~techemporium/browzos.php</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~fosslinux/?C=N;O=A</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~fosslinux/?C=M;O=D</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~fosslinux/?C=S;O=D</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~fosslinux/?C=D;O=D</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.51</priority>
</url>
<url>
<loc>https://www.thunix.net/~techemporium/gpl-3.0.php</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.41</priority>
</url>
<url>
<loc>https://www.thunix.net/~techemporium/mit_license.php</loc>
<lastmod>2019-07-17T01:25:07+00:00</lastmod>
<priority>0.41</priority>
</url>
</urlset>

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
header('Content-Type: application/json; charset=utf-8');
header('X-Content-Type-Options: nosniff');
$rootDir = dirname(__DIR__, 2);
if (!is_dir($rootDir)) {
http_response_code(500);
echo json_encode(['error' => 'Invalid root directory'], JSON_UNESCAPED_SLASHES);
exit;
}
function json_out(array $data, int $status = 200): void
{
http_response_code($status);
try {
echo json_encode(
$data,
JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
);
} catch (Throwable $e) {
http_response_code(500);
echo '{"error":"JSON encoding failed"}';
}
exit;
}

58
terminal/api/menu.php Normal file
View File

@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
require __DIR__ . '/terminal/_bootstrap.php';
$file = $rootDir . '/includes/sidebar.md';
if (!is_file($file)) {
json_out(['sections' => []]);
}
$md = file_get_contents($file);
if ($md === false) {
json_out(['sections' => []]);
}
$lines = preg_split('/\r\n|\n|\r/', $md) ?: [];
$sections = [];
$current = null;
foreach ($lines as $line) {
$raw = rtrim($line);
// Section header: "- Title"
if (preg_match('/^\-\s{2,}(.+)$/', $raw, $m)) {
if ($current !== null) {
$sections[] = $current;
}
$current = [
'title' => trim($m[1]),
'items' => [],
];
continue;
}
// Menu item: " - [Text](Href)"
if ($current !== null && preg_match('/^\s+\-\s{2,}\[(.+?)\]\((.+?)\)\s*$/', $raw, $m)) {
$text = trim($m[1]);
$href = trim($m[2]);
$internal = str_starts_with($href, '/');
$slug = $internal ? ltrim(parse_url($href, PHP_URL_PATH) ?? '', '/') : '';
$current['items'][] = [
'text' => $text,
'href' => $href,
'internal' => $internal,
'slug' => $slug,
];
continue;
}
}
if ($current !== null) {
$sections[] = $current;
}
json_out(['sections' => $sections]);

53
terminal/api/page.php Normal file
View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
require __DIR__ . '/_bootstrap.php';
$p = $_GET['p'] ?? '';
if (!is_string($p)) {
json_out(['error' => 'Invalid page'], 400);
}
$slug = trim($p);
$slug = ltrim($slug, '/');
$slug = preg_replace('/\?.*$/', '', $slug) ?? $slug;
if ($slug === '' || !preg_match('/^[A-Za-z0-9][A-Za-z0-9_-]*$/', $slug)) {
json_out(['error' => 'Invalid page'], 400);
}
if (preg_match('/^success\d+$/', $slug) === 1) {
json_out(['error' => 'Not found'], 404);
}
$file = $rootDir . '/articles/' . $slug . '.md';
if (!is_file($file)) {
json_out(['error' => 'Not found'], 404);
}
$md = file_get_contents($file);
if ($md === false) {
json_out(['error' => 'Failed to read page'], 500);
}
$parsedownPath = $rootDir . '/parsedown-1.7.3/Parsedown.php';
$extraPath = $rootDir . '/parsedown-extra-0.7.1/ParsedownExtra.php';
if (is_file($parsedownPath)) {
require_once $parsedownPath;
}
if (is_file($extraPath)) {
require_once $extraPath;
}
$html = '';
if (class_exists('ParsedownExtra')) {
$pd = new ParsedownExtra();
$html = $pd->text($md);
}
json_out([
'slug' => $slug,
'markdown' => $md,
'html' => $html,
]);

51
terminal/api/pages.php Normal file
View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
require __DIR__ . '/_bootstrap.php';
$articlesDir = $rootDir . '/articles';
if (!is_dir($articlesDir)) {
json_out(['pages' => []]);
}
$pages = [];
$files = glob($articlesDir . '/*.md') ?: [];
sort($files);
foreach ($files as $file) {
$slug = basename($file, '.md');
if (preg_match('/^success\d+$/', $slug) === 1) {
continue;
}
$title = $slug;
$fh = fopen($file, 'rb');
if ($fh !== false) {
for ($i = 0; $i < 20; $i++) {
$line = fgets($fh);
if ($line === false) {
break;
}
$line = trim($line);
if ($line === '') {
continue;
}
if (preg_match('/^#\s+(.+)$/', $line, $m)) {
$title = trim($m[1]);
break;
}
$title = mb_substr($line, 0, 80);
break;
}
fclose($fh);
}
$pages[] = [
'slug' => $slug,
'title' => $title,
];
}
json_out(['pages' => $pages]);

49
terminal/api/server.php Normal file
View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
require __DIR__ . '/_bootstrap.php';
$candidates = [
$rootDir . '/report',
$rootDir . '/includes/report',
];
$report = null;
foreach ($candidates as $cand) {
if (is_file($cand)) {
$report = $cand;
break;
}
}
if ($report === null) {
json_out(['rows' => [], 'lastUpdated' => null]);
}
$rows = [];
$fh = fopen($report, 'rb');
if ($fh === false) {
json_out(['rows' => [], 'lastUpdated' => null]);
}
while (($line = fgets($fh)) !== false) {
$line = trim($line);
if ($line === '') {
continue;
}
$parts = str_getcsv($line);
if (count($parts) < 3) {
continue;
}
$rows[] = [
'host' => (string)$parts[0],
'check' => (string)$parts[1],
'status' => (string)$parts[2],
];
}
fclose($fh);
$mtime = @filemtime($report);
$last = $mtime ? gmdate('c', (int)$mtime) : null;
json_out(['rows' => $rows, 'lastUpdated' => $last]);

42
terminal/api/users.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
require __DIR__ . '/_bootstrap.php';
$siteRoot = '//' . ($_SERVER['HTTP_HOST'] ?? 'localhost');
$skelIndex = '/etc/skel/public_html/index.html';
$skelIndexCksum = is_file($skelIndex) ? @md5_file($skelIndex) : null;
$users = [];
$homes = glob('/home/*', GLOB_ONLYDIR) ?: [];
foreach ($homes as $homeDir) {
$user = basename($homeDir);
if ($user === '' || $user === 'lost+found') {
continue;
}
$userIndex = $homeDir . '/public_html/index.html';
$userPub = $homeDir . '/public_html';
if (!is_dir($userPub)) {
continue;
}
$hasCustomIndex = false;
if (is_file($userIndex) && $skelIndexCksum !== null) {
$userCksum = @md5_file($userIndex);
$hasCustomIndex = ($userCksum !== false && $userCksum !== $skelIndexCksum);
} elseif (is_file($userIndex)) {
$hasCustomIndex = true;
}
$users[] = [
'username' => $user,
'url' => $siteRoot . '/~' . rawurlencode($user) . '/',
'hasContent' => $hasCustomIndex,
];
}
json_out(['users' => $users]);

159
terminal/index.php Normal file
View File

@@ -0,0 +1,159 @@
<?php
declare(strict_types=1);
header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: no-referrer');
header('Permissions-Policy: geolocation=(), microphone=(), camera=()');
?><!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>thunix terminal</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<noscript><meta http-equiv="refresh" content="0;url=/main"></noscript>
<!-- xterm core styles -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xterm/xterm@6.0.0/css/xterm.css">
<style>
:root{
--mono: "Departure Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bg: #111;
--amber: #edb200;
--amber-txt: #ffc828;
--panel: rgba(255, 255, 255, 0.03);
--border: rgba(255, 255, 255, 0.08);
}
*{ box-sizing:border-box; }
html, body{
margin:0;
padding:0;
height:100%;
width:100%;
overflow:hidden;
background: var(--bg);
color: var(--amber);
font-family: var(--mono);
}
body::before{
content:'';
position:fixed;
inset:0;
pointer-events:none;
z-index:2;
background: linear-gradient(to bottom, transparent 50%, rgba(0,0,0,0.32) 51%);
background-size: 100% 4px;
}
#wrap{
position:relative;
z-index:1;
height:100%;
display:flex;
flex-direction:column;
padding: 6vh 0 6vh 0;
gap: 10px;
}
#head{
width: min(92vw, 1400px);
margin: 0 auto;
font-size: clamp(18px, 3vw, 44px);
text-shadow: 0 0 1.75rem rgba(237,178,0,0.55);
line-height:1.1;
}
#head small{
display:block;
font-size: 0.8rem;
opacity: 0.85;
margin-top: 8px;
text-shadow:none;
}
#main{
width: min(92vw, 1400px);
margin: 0 auto;
flex: 1;
display: grid;
grid-template-columns: 1.05fr 1.25fr;
gap: 12px;
align-items: stretch;
}
#terminalHost,
#contentHost{
background: var(--panel);
border: 1px solid var(--border);
border-radius: 6px;
overflow: hidden;
box-shadow: 0 0 24px rgba(237,178,0,0.09);
min-height: 0;
}
#terminal{ height: 100%; width: 100%; }
#contentFrame{
width: 100%;
height: 100%;
border: 0;
background: var(--bg);
}
@media (max-width: 1050px){
#main{ grid-template-columns: 1fr; grid-template-rows: 48vh 1fr; }
}
#terminalHost .xterm-rows a,
#terminalHost .xterm-screen a{
color: var(--amber-txt) !important;
text-decoration: underline;
text-decoration-thickness: 2px;
text-underline-offset: 3px;
text-shadow: 0 0 0.85rem rgba(237,178,0,0.30);
}
#terminalHost .xterm-rows a:hover,
#terminalHost .xterm-screen a:hover{
filter: brightness(1.08);
text-shadow: 0 0 1.25rem rgba(237,178,0,0.55);
}
</style>
</head>
<body>
<noscript>
<div style="max-width: 900px; margin: 2rem auto; padding: 1.25rem 1.5rem; border: 1px solid rgba(255,255,255,0.12); border-radius: 14px; background: rgba(0,0,0,0.55); color: #e6e6e6; font-family: system-ui, -apple-system, Segoe UI, sans-serif;">
<h1 style="margin: 0 0 0.6rem 0; font-size: 1.35rem; font-weight: 700;">Terminal mode needs JavaScript</h1>
<p style="margin: 0; opacity: 0.9; line-height: 1.4;">JavaScript is disabled, so the terminal UI cant run. Redirecting you to the classic site… If youre not redirected, use <a href="/main" style="color: #6ec5ff; text-decoration: underline;">the classic site</a>.</p>
</div>
</noscript>
<div id="wrap">
<div id="head">
🌻 thunix
<small>Type <strong>help</strong>. Click inside the terminal to focus.</small>
</div>
<div id="main">
<div id="terminalHost">
<div id="terminal" aria-label="Terminal"></div>
</div>
<div id="contentHost" aria-label="Content">
<iframe
id="contentFrame"
src="/terminal/view.php?page=main"
title="thunix content"
referrerpolicy="no-referrer"
loading="eager"
></iframe>
</div>
</div>
</div>
<script type="module" src="/terminal/terminal.js"></script>
</body>
</html>

545
terminal/terminal.js Normal file
View File

@@ -0,0 +1,545 @@
// thunix terminal UI powered by xterm.js (ESM via jsDelivr).
import { Terminal } from "https://cdn.jsdelivr.net/npm/@xterm/xterm@6.0.0/+esm";
import { FitAddon } from "https://cdn.jsdelivr.net/npm/@xterm/addon-fit@0.11.0/+esm";
import { WebLinksAddon } from "https://cdn.jsdelivr.net/npm/@xterm/addon-web-links@0.12.0/+esm";
const MODULE_BASE = new URL(".", import.meta.url);
const urlFromBase = (path) => new URL(path, MODULE_BASE).toString();
const DEFAULT_WEBMAIL_PATH = "/webmail/";
const ESC = "\x1b";
const CSI = `${ESC}[`;
const OSC = `${ESC}]`;
const ANSI = {
reset: `${CSI}0m`,
bold: `${CSI}1m`,
dim: `${CSI}2m`,
underline: `${CSI}4m`,
noUnderline: `${CSI}24m`,
clrLine: `${CSI}2K`,
fgBrightYellow: `${CSI}93m`,
fgWhite: `${CSI}37m`,
};
function osc8(url, text) {
const BEL = "\x07";
return `${OSC}8;;${url}${BEL}${text}${OSC}8;;${BEL}`;
}
function absolutizeUrl(href) {
if (!href) return href;
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(href)) return href;
if (href.startsWith("//")) return `${location.protocol}${href}`;
if (href.startsWith("/")) return `${location.origin}${href}`;
return new URL(href, location.href).toString();
}
function renderInlineLinks(line) {
return line.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, text, href) => {
const url = absolutizeUrl(String(href).trim());
const label = `${ANSI.underline}${ANSI.fgBrightYellow}${text}${ANSI.reset}`;
return osc8(url, label);
});
}
function stripHtmlToText(html) {
let s = String(html || "");
s = s.replace(/<\s*br\s*\/?\s*>/gi, "\n");
s = s.replace(/<\s*\/(p|div|tr|li|table|form|h1|h2|h3|ul|ol)\s*>/gi, "\n");
s = s.replace(/<\s*(p|div|tr|li|table|form|h1|h2|h3|ul|ol)(\s[^>]*)?>/gi, "\n");
s = s.replace(/<a\s+[^>]*href=['"]([^'"]+)['"][^>]*>(.*?)<\/a>/gi, (_m, href, text) => {
const cleanText = String(text).replace(/<[^>]+>/g, "").trim() || href;
return `[${cleanText}](${href})`;
});
s = s.replace(/<[^>]+>/g, "");
s = s.replace(/&nbsp;/g, " ");
s = s.replace(/&amp;/g, "&");
s = s.replace(/&lt;/g, "<");
s = s.replace(/&gt;/g, ">");
s = s.replace(/&quot;/g, '"');
s = s.replace(/&#39;/g, "'");
return s;
}
function renderMarkdown(md) {
const input = stripHtmlToText(md);
const out = [];
const lines = input.replace(/\r\n/g, "\n").split("\n");
let inCode = false;
for (const raw of lines) {
let line = raw;
if (/^\s*```/.test(line)) {
inCode = !inCode;
out.push(inCode ? `${ANSI.dim}--- code ---${ANSI.reset}` : `${ANSI.dim}--- end ---${ANSI.reset}`);
continue;
}
if (inCode) {
out.push(line);
continue;
}
if (/^\s*#\s+/.test(line)) {
const title = line.replace(/^\s*#\s+/, "").trim();
out.push(`${ANSI.bold}${title}${ANSI.reset}`);
out.push(`${ANSI.dim}${"=".repeat(Math.min(78, title.length || 1))}${ANSI.reset}`);
continue;
}
if (/^\s*##\s+/.test(line)) {
const title = line.replace(/^\s*##\s+/, "").trim();
out.push(`${ANSI.bold}${title}${ANSI.reset}`);
out.push(`${ANSI.dim}${"-".repeat(Math.min(78, title.length || 1))}${ANSI.reset}`);
continue;
}
const mBullet = line.match(/^\s*[-*]\s+(.*)$/);
if (mBullet) {
line = ` - ${mBullet[1]}`;
}
line = line.replace(/\s+$/g, "");
line = renderInlineLinks(line);
out.push(line);
}
return out.join("\r\n");
}
class ThunixTerminal {
constructor(hostEl, frameEl) {
this.el = hostEl;
this.frame = frameEl;
this.term = null;
this.fit = new FitAddon();
this.buffer = "";
this.history = [];
this.historyIdx = -1;
this.pages = new Map();
this.menu = null;
this.webLinks = new WebLinksAddon((ev, uri) => {
try {
ev?.preventDefault?.();
} catch {
}
this.handleLinkActivate(uri);
});
this.init();
}
init() {
this.term = new Terminal({
cursorBlink: true,
convertEol: true,
scrollback: 4000,
fontFamily:
'"Departure Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
fontSize: 18,
theme: {
background: "#111111",
foreground: "#edb200",
cursor: "#ffc828",
selection: "rgba(255, 200, 40, 0.25)",
black: "#000000",
brightYellow: "#ffc828",
},
});
this.term.loadAddon(this.fit);
this.term.loadAddon(this.webLinks);
this.term.open(this.el);
this.fit.fit();
window.addEventListener("resize", () => this.fit.fit());
this.el.addEventListener("mousedown", () => this.term.focus());
this.term.focus();
this.term.onKey((e) => this.onKey(e));
this.boot();
}
writeln(s = "") {
this.term.writeln(s);
}
write(s = "") {
this.term.write(s);
}
prompt() {
this.write(`\r\n${ANSI.bold}guest@thunix${ANSI.reset}:${ANSI.fgWhite}~${ANSI.reset}$ `);
}
redrawInput(newValue) {
this.write(`\r${ANSI.clrLine}${ANSI.bold}guest@thunix${ANSI.reset}:${ANSI.fgWhite}~${ANSI.reset}$ ${newValue}`);
}
async boot() {
this.writeln(`${ANSI.bold}thunix terminal${ANSI.reset}`);
this.writeln(`${ANSI.dim}Terminal commands + real HTML panel so forms actually work.${ANSI.reset}`);
this.writeln("");
await Promise.allSettled([this.loadPages(), this.loadMenu()]);
const hash = (location.hash || "").replace(/^#/, "").trim();
const initial = hash && this.normalizeSlug(hash);
if (initial) {
this.openInPanel(initial);
} else {
this.openInPanel("main");
}
this.writeln(`${ANSI.dim}Type ${ANSI.reset}${ANSI.bold}help${ANSI.reset}${ANSI.dim} for commands.${ANSI.reset}`);
this.prompt();
}
async loadPages() {
const res = await fetch(urlFromBase("api/pages.php"), { cache: "no-store" });
if (!res.ok) return;
const data = await res.json();
if (!data?.pages) return;
for (const p of data.pages) {
this.pages.set(p.slug, p.title || p.slug);
}
}
async loadMenu() {
const res = await fetch(urlFromBase("api/menu.php"), { cache: "no-store" });
if (!res.ok) return;
this.menu = await res.json();
}
handleLinkActivate(uri) {
const u = (() => {
try {
return new URL(uri, location.origin);
} catch {
return null;
}
})();
if (!u) {
window.open(uri, "_blank", "noopener");
return;
}
if (u.pathname.endsWith("/terminal/view.php")) {
const p = u.searchParams.get("page") || "";
if (p) {
this.openInPanel(p);
return;
}
}
if (u.origin === location.origin && u.pathname.startsWith("/")) {
const slug = this.normalizeSlug(u.pathname.replace(/^\/+/, ""));
if (slug && this.pages.has(slug)) {
this.openInPanel(slug);
return;
}
}
window.open(u.toString(), "_blank", "noopener");
}
onKey({ key, domEvent }) {
const ev = domEvent;
if (ev.ctrlKey && ev.key.toLowerCase() === "l") {
ev.preventDefault();
this.cmdClear();
return;
}
if (ev.ctrlKey && ev.key.toLowerCase() === "c") {
ev.preventDefault();
this.write("^C");
this.buffer = "";
this.historyIdx = -1;
this.prompt();
return;
}
if (ev.key === "Enter") {
const line = this.buffer.trim();
this.buffer = "";
this.historyIdx = -1;
this.write("\r\n");
if (line) this.history.unshift(line);
this.run(line);
return;
}
if (ev.key === "Backspace") {
if (this.buffer.length > 0) {
this.buffer = this.buffer.slice(0, -1);
this.write("\b \b");
}
return;
}
if (ev.key === "ArrowUp") {
if (this.history.length === 0) return;
if (this.historyIdx + 1 < this.history.length) this.historyIdx++;
const next = this.history[this.historyIdx] ?? "";
this.buffer = next;
this.redrawInput(this.buffer);
return;
}
if (ev.key === "ArrowDown") {
if (this.history.length === 0) return;
if (this.historyIdx > 0) this.historyIdx--;
else this.historyIdx = -1;
const next = this.historyIdx >= 0 ? (this.history[this.historyIdx] ?? "") : "";
this.buffer = next;
this.redrawInput(this.buffer);
return;
}
if (!ev.altKey && !ev.ctrlKey && !ev.metaKey && key && key.length === 1) {
this.buffer += key;
this.write(key);
}
}
async run(line) {
if (!line) {
this.prompt();
return;
}
const [cmdRaw, ...args] = line.split(/\s+/);
const cmd = cmdRaw.toLowerCase();
switch (cmd) {
case "help":
this.cmdHelp();
break;
case "clear":
this.cmdClear();
break;
case "menu":
await this.cmdMenu();
break;
case "pages":
case "ls":
await this.cmdPages();
break;
case "open":
await this.cmdOpen(args.join(" "));
break;
case "cat":
await this.cmdCat(args.join(" "));
break;
case "web":
this.cmdWeb(args.join(" "));
break;
case "webmail":
case "mail":
this.cmdWebmail(args.join(" "));
break;
case "users":
await this.cmdOpen("users");
break;
case "server":
await this.cmdOpen("server");
break;
case "news":
await this.cmdOpen("news");
break;
case "main":
case "home":
await this.cmdOpen("main");
break;
default:
this.writeln(`${ANSI.dim}Unknown command:${ANSI.reset} ${cmdRaw}`);
this.writeln(`${ANSI.dim}Try:${ANSI.reset} ${ANSI.bold}help${ANSI.reset}`);
break;
}
this.prompt();
}
cmdHelp() {
this.writeln(`${ANSI.bold}Commands${ANSI.reset}`);
this.writeln(`${ANSI.dim}help${ANSI.reset} Show this help`);
this.writeln(`${ANSI.dim}pages | ls${ANSI.reset} List available content pages`);
this.writeln(`${ANSI.dim}open <page>${ANSI.reset} Load a page in the panel`);
this.writeln(`${ANSI.dim}web <page>${ANSI.reset} Print web URLs for a page`);
this.writeln(`${ANSI.dim}webmail [url]${ANSI.reset} Open webmail in a new tab (alias: mail)`);
this.writeln(`${ANSI.dim}clear${ANSI.reset} Clear the terminal (Ctrl+L)`);
this.writeln("");
this.writeln(`${ANSI.dim}Aliases:${ANSI.reset} home, main, users, server, news, mail`);
}
cmdClear() {
this.term.clear();
this.term.reset();
this.writeln(`${ANSI.bold}thunix terminal${ANSI.reset}`);
}
async cmdMenu() {
if (!this.menu) await this.loadMenu();
const menu = this.menu;
if (!menu?.sections?.length) {
this.writeln(`${ANSI.dim}Menu not available.${ANSI.reset}`);
return;
}
for (const section of menu.sections) {
this.writeln("");
this.writeln(`${ANSI.bold}${section.title}${ANSI.reset}`);
this.writeln(`${ANSI.dim}${"-".repeat(Math.min(78, section.title.length || 1))}${ANSI.reset}`);
for (const item of section.items) {
const href = item.internal ? `${location.origin}/${item.slug}` : absolutizeUrl(item.href);
const label = `${ANSI.underline}${ANSI.fgBrightYellow}${item.text}${ANSI.reset}`;
const link = osc8(href, label);
const hint = item.internal ? `${ANSI.dim} (open ${item.slug})${ANSI.reset}` : "";
this.writeln(`${link}${hint}`);
}
}
}
async cmdPages() {
if (this.pages.size === 0) await this.loadPages();
if (this.pages.size === 0) {
this.writeln(`${ANSI.dim}No pages found.${ANSI.reset}`);
return;
}
this.writeln(`${ANSI.bold}Pages${ANSI.reset}`);
const slugs = [...this.pages.keys()].sort();
this.writeln(slugs.map((s) => ` - ${s}`).join("\r\n"));
}
cmdWeb(arg) {
const slug = this.normalizeSlug(arg);
if (!slug) {
this.writeln(`${ANSI.dim}Usage:${ANSI.reset} web <page>`);
return;
}
const classic = `${location.origin}/${slug}`;
const panelUrl = new URL("view.php", MODULE_BASE);
panelUrl.searchParams.set("page", slug);
const panel = panelUrl.toString();
this.writeln(`${ANSI.dim}Classic:${ANSI.reset} ${osc8(classic, `${ANSI.underline}${ANSI.fgBrightYellow}${classic}${ANSI.reset}`)}`);
this.writeln(`${ANSI.dim}Panel:${ANSI.reset} ${osc8(panel, `${ANSI.underline}${ANSI.fgBrightYellow}${panel}${ANSI.reset}`)}`);
}
cmdWebmail(arg) {
const raw = String(arg || "").trim();
const configured = (() => {
try {
const v = window.THUNIX_WEBMAIL_URL;
return typeof v === "string" ? v.trim() : "";
} catch {
return "";
}
})();
const target = raw || configured || DEFAULT_WEBMAIL_PATH;
const url = absolutizeUrl(target);
window.open(url, "_blank", "noopener");
const label = `${ANSI.underline}${ANSI.fgBrightYellow}${url}${ANSI.reset}`;
this.writeln(`${ANSI.dim}Opened webmail:${ANSI.reset} ${osc8(url, label)}`);
if (!raw && !configured && DEFAULT_WEBMAIL_PATH !== "/webmail/") {
this.writeln(`${ANSI.dim}Hint:${ANSI.reset} set window.THUNIX_WEBMAIL_URL if your webmail lives elsewhere.`);
} else if (!raw && !configured) {
this.writeln(
`${ANSI.dim}Hint:${ANSI.reset} if your webmail isn't at ${ANSI.bold}${DEFAULT_WEBMAIL_PATH}${ANSI.reset}${ANSI.dim}, set window.THUNIX_WEBMAIL_URL (or run: webmail <url>).${ANSI.reset}`
);
}
}
normalizeSlug(arg) {
if (!arg) return "";
let s = String(arg).trim();
if (s.startsWith("/")) s = s.replace(/^\/+/, "");
if (s.includes("?")) s = s.split("?")[0];
if (s === "") return "";
return s;
}
openInPanel(slug) {
if (!this.frame) return;
const clean = this.normalizeSlug(slug);
this.frame.src = `${urlFromBase("view.php")}?page=${encodeURIComponent(clean)}`;
try {
history.replaceState(null, "", `#${encodeURIComponent(clean)}`);
} catch {
}
}
async cmdOpen(arg) {
const slug = this.normalizeSlug(arg);
if (!slug) {
this.writeln(`${ANSI.dim}Usage:${ANSI.reset} open <page>`);
return;
}
if (/^https?:\/\//i.test(slug) || slug.startsWith("//")) {
const url = absolutizeUrl(slug);
window.open(url, "_blank", "noopener");
this.writeln(`${ANSI.dim}Opened externally:${ANSI.reset} ${osc8(url, `${ANSI.underline}${ANSI.fgBrightYellow}${url}${ANSI.reset}`)}`);
return;
}
if (this.pages.size === 0) await this.loadPages();
if (this.pages.size && !this.pages.has(slug) && !/^success\d+$/.test(slug)) {
this.writeln(`${ANSI.dim}No such page:${ANSI.reset} ${slug}`);
this.writeln(`${ANSI.dim}Try:${ANSI.reset} pages`);
return;
}
this.openInPanel(slug);
this.writeln(`${ANSI.dim}Loaded in panel:${ANSI.reset} ${ANSI.bold}${slug}${ANSI.reset}`);
}
async cmdCat(arg) {
const slug = this.normalizeSlug(arg);
if (!slug) {
this.writeln(`${ANSI.dim}Usage:${ANSI.reset} cat <page>`);
return;
}
const res = await fetch(`${urlFromBase("api/page.php")}?p=${encodeURIComponent(slug)}`, { cache: "no-store" });
if (!res.ok) {
this.writeln(`${ANSI.dim}No such page:${ANSI.reset} ${slug}`);
return;
}
const data = await res.json();
const md = String(data?.markdown ?? "");
this.writeln("");
this.writeln(renderMarkdown(md));
}
}
document.addEventListener("DOMContentLoaded", () => {
const host = document.getElementById("terminal");
const frame = document.getElementById("contentFrame");
if (!host) return;
new ThunixTerminal(host, frame);
});

234
terminal/view.php Normal file
View File

@@ -0,0 +1,234 @@
<?php
declare(strict_types=1);
// Render wiki content using the *same* parser stack as wiki.php,
require __DIR__ . '/../config.php';
require __DIR__ . '/../parsedown-1.7.3/Parsedown.php';
require __DIR__ . '/../parsedown-extra-0.7.1/ParsedownExtra.php';
$page = isset($_GET['page']) ? (string) $_GET['page'] : 'main';
if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/', $page)) {
http_response_code(400);
header('Content-Type: text/plain; charset=UTF-8');
echo "Bad page name.";
exit;
}
$contentPath = $doc_root . '/articles/' . $page . '.md';
if (!is_file($contentPath)) {
http_response_code(404);
header('Content-Type: text/plain; charset=UTF-8');
echo "Not found.";
exit;
}
$ParsedownExtra = new ParsedownExtra();
$md = file_get_contents($contentPath);
if ($md === false) {
http_response_code(500);
header('Content-Type: text/plain; charset=UTF-8');
echo "Failed to read page.";
exit;
}
$html = $ParsedownExtra->text($md);
if ($page === 'users' || $page === 'server') {
$inc = $doc_root . '/includes/' . $page . '.php';
if (is_file($inc)) {
ob_start();
require $inc;
$html .= (string) ob_get_clean();
}
}
$knownPages = [];
foreach (glob($doc_root . '/articles/*.md') ?: [] as $file) {
$slug = basename($file, '.md');
$knownPages[$slug] = true;
}
$rewriteFormActions = function (string $action): string {
$path = parse_url($action, PHP_URL_PATH);
if (!is_string($path) || $path === '') {
$path = $action;
}
$pathLower = strtolower($path);
if (!preg_match('~(^|/)(includes/(contact|signup)\.php)$~', $pathLower)) {
return $action;
}
$parts = parse_url($action);
if ($parts === false) {
if (strpos($action, 'terminal=1') !== false) {
return $action;
}
return (strpos($action, '?') !== false) ? ($action . '&terminal=1') : ($action . '?terminal=1');
}
$query = [];
if (isset($parts['query'])) {
parse_str((string) $parts['query'], $query);
}
$query['terminal'] = '1';
$queryString = http_build_query($query);
$rebuilt = '';
if (isset($parts['scheme'])) {
$rebuilt .= $parts['scheme'] . '://';
} elseif (str_starts_with($action, '//')) {
$rebuilt .= '//';
}
if (isset($parts['user'])) {
$rebuilt .= $parts['user'];
if (isset($parts['pass'])) {
$rebuilt .= ':' . $parts['pass'];
}
$rebuilt .= '@';
}
if (isset($parts['host'])) {
$rebuilt .= $parts['host'];
}
if (isset($parts['port'])) {
$rebuilt .= ':' . $parts['port'];
}
$rebuilt .= $parts['path'] ?? '';
if ($queryString !== '') {
$rebuilt .= '?' . $queryString;
}
if (isset($parts['fragment'])) {
$rebuilt .= '#' . $parts['fragment'];
}
return $rebuilt;
};
$isTerminalSuccessFormTarget = function (string $action): bool {
$path = parse_url($action, PHP_URL_PATH);
if (!is_string($path) || $path === '') {
$path = $action;
}
$pathLower = strtolower($path);
return preg_match('~(^|/)(includes/(contact|signup)\.php)$~', $pathLower) === 1;
};
$html = preg_replace_callback(
'~(<form\b[^>]*\baction\s*=\s*)(["\'])([^"\']+)(\2)~i',
function (array $m) use ($rewriteFormActions): string {
$new = $rewriteFormActions((string) $m[3]);
return $m[1] . $m[2] . $new . $m[4];
},
$html
);
$html = preg_replace_callback(
'~(<form\b[^>]*>)~i',
function (array $m) use ($rewriteFormActions, $isTerminalSuccessFormTarget): string {
$tag = $m[1];
if (preg_match('~\baction\s*=\s*(["\'])([^"\']+)\1~i', $tag, $am) !== 1) {
return $tag;
}
$action = (string) $am[2];
if ($isTerminalSuccessFormTarget($action) === false) {
return $tag;
}
$newAction = $rewriteFormActions($action);
$tag = preg_replace(
'~\baction\s*=\s*(["\'])([^"\']+)\1~i',
'action=' . $am[1] . $newAction . $am[1],
$tag,
1
);
return $tag . "\n" . '<input type="hidden" name="terminal" value="1">';
},
$html
);
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML(
'<!doctype html><html><head><meta charset="utf-8"></head><body><div id="content">' . $html . '</div></body></html>',
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
);
foreach ($dom->getElementsByTagName('a') as $a) {
$href = $a->getAttribute('href');
if ($href === '' || str_starts_with($href, '#')) {
continue;
}
if (preg_match('/^[a-zA-Z][a-zA-Z0-9+.-]*:/', $href) === 1) {
$a->setAttribute('target', '_blank');
$a->setAttribute('rel', 'noopener');
continue;
}
if (str_starts_with($href, '/')) {
$path = parse_url($href, PHP_URL_PATH) ?? '';
$slug = ltrim($path, '/');
if ($slug !== '' && isset($knownPages[$slug])) {
$a->setAttribute('href', './view.php?page=' . rawurlencode($slug));
continue;
}
$a->setAttribute('target', '_blank');
$a->setAttribute('rel', 'noopener');
continue;
}
$a->setAttribute('target', '_blank');
$a->setAttribute('rel', 'noopener');
}
foreach ($dom->getElementsByTagName('form') as $form) {
$action = $form->getAttribute('action');
if ($action !== '') {
$form->setAttribute('action', $rewriteFormActions($action));
}
}
$finalHtml = $dom->saveHTML();
libxml_clear_errors();
header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: no-referrer');
header('Content-Type: text/html; charset=UTF-8');
?><!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo htmlspecialchars($site_name . ' - ' . $page, ENT_QUOTES, 'UTF-8'); ?></title>
<link rel="stylesheet" type="text/css" href="<?php echo htmlspecialchars($site_root . '/includes/terminal.css', ENT_QUOTES, 'UTF-8'); ?>">
</head>
<body>
<?php
$dom2 = new DOMDocument();
libxml_use_internal_errors(true);
$dom2->loadHTML($finalHtml);
libxml_clear_errors();
$content = $dom2->getElementById('content');
if ($content === null) {
echo $finalHtml;
} else {
echo $dom2->saveHTML($content);
}
?>
</body>
</html>

1460
tilde.json

File diff suppressed because one or more lines are too long

View File

@@ -8,24 +8,20 @@ include('config.php');
include('parsedown-1.7.3/Parsedown.php'); include('parsedown-1.7.3/Parsedown.php');
include('parsedown-extra-0.7.1/ParsedownExtra.php'); include('parsedown-extra-0.7.1/ParsedownExtra.php');
$page = $_GET['page']; if(isset($_GET['page']))
$style = $_GET['style']; $page = $_GET['page'];
else
$page = "main";
if(isset($_GET['style']))
$site_style = $_GET['style'];
$Parsedown = new Parsedown(); $Parsedown = new Parsedown();
$Parsedown->setMarkupEscaped(true); $Parsedown->setMarkupEscaped(true);
$ParsedownExtra = new ParsedownExtra(); $ParsedownExtra = new ParsedownExtra();
if ( $page == "") { if (empty($site_style))
$page = "main";
}
if ( $style == "") {
if ( $site_style == "") {
$site_style="site"; $site_style="site";
}
}
else {
$site_style=$style;
}
$header = file_get_contents("$doc_root/includes/header.md"); $header = file_get_contents("$doc_root/includes/header.md");
$sidebar = file_get_contents("$doc_root/includes/sidebar.md"); $sidebar = file_get_contents("$doc_root/includes/sidebar.md");
@@ -67,6 +63,13 @@ print " </div>
echo $ParsedownExtra->text($content); echo $ParsedownExtra->text($content);
switch ($page)
{
case 'users':
case 'server':
require "includes/$page.php";
}
print " </div> print " </div>
<!-- End Body --> <!-- End Body -->
@@ -79,7 +82,8 @@ print " </div>
echo $Parsedown->text($footer); echo $Parsedown->text($footer);
print " </div> print " <a href=\"https://github.com/ThunixdotNet/www\">Site Source</a> | <a href=\"https://github.com/ThunixdotNet/www/tree/master/articles/$page.md\">Page Source</a>
</div>
<!-- End Footer --> <!-- End Footer -->
</body> </body>