Gemini server written in Crystal
修订版 | dbbae5dcc82d5c3f93f3bcecdc04dce8b5dd1072 (tree) |
---|---|
时间 | 2023-12-04 09:17:10 |
作者 | Remilia Scarlet <alexa@part...> |
Commiter | Remilia Scarlet |
Moved the repo
@@ -1,193 +0,0 @@ | ||
1 | -# Installing Aya as a System-Wide Program | |
2 | - | |
3 | -This document describes how to install Aya as a system-wide program. Typically | |
4 | -this is not needed if you just want to server files as a non-root user, but it's | |
5 | -an option should you wish to install Aya in a more traditional way. | |
6 | - | |
7 | -## Prerequisites | |
8 | - | |
9 | -You will need: | |
10 | - | |
11 | -* A Linux operating system with root access. | |
12 | -* A compiled binary of Aya, or the source code to build a binary yourself. | |
13 | -* The `nohup` program (this may be a built-in for your shell). | |
14 | - | |
15 | -Once you have these met, you will need to decide a few things ahead of time: | |
16 | - | |
17 | -* Where the server root will be (e.g. `/var/www/gemini/`) | |
18 | -* Where you want your log files (e.g. `/var/log/aya/`) | |
19 | -* The username and group you want to Aya to switch to after starting. | |
20 | - | |
21 | -### A Few Notes About Aya's Behavior | |
22 | - | |
23 | -When Aya starts up, it first loads (as the user/group it was started with) a | |
24 | -configuration file and the MIME file (if any). After this, Aya checks to see if | |
25 | -the configuration file specifies a UID and GID that it should change to. If | |
26 | -these exist, Aya will change the process's real and effective user ID group ID | |
27 | -to the values specified. Otherwise, it will continue to run as the user/group | |
28 | -that started it. | |
29 | - | |
30 | -Aya will then check to see if its process is running as root, even after | |
31 | -changing user/group IDs. If it is, Aya will print a warning (because allowing | |
32 | -Aya to continue to run as root is a bad idea). | |
33 | - | |
34 | -After this, the log files are opened for appending (or created if they don't | |
35 | -exist) if needed, and the server beings listening for connections. Because the | |
36 | -user/group ID has already changed, this implies that Aya cannot listen on | |
37 | -unprivileged ports (i.e. ports below 1024). Since Gemini runs on port 1965 by | |
38 | -default, this should not cause any problems. | |
39 | - | |
40 | - | |
41 | -## Creating Users, Groups, and Directories | |
42 | - | |
43 | -The first step is to create the `/etc/aya/` directory as root, set it up with | |
44 | -the correct permissions, and copy the example configuration over. This | |
45 | -directory and its files should be owned by root. | |
46 | - | |
47 | -``` | |
48 | -# mkdir /etc/aya | |
49 | -# cp -v /path/to/sample-config.yaml /etc/aya/aya-config.yaml | |
50 | -# chown -Rv root:root /etc/aya | |
51 | -# chmod -v 755 /etc/aya | |
52 | -# chmod -v 640 /etc/aya/aya-config.yaml | |
53 | -``` | |
54 | - | |
55 | -Next, you will need to add a new user and group to your system. This is because | |
56 | -allowing Aya to continue to run as root after it starts up is a bad idea. You | |
57 | -may need to change the user ID and group ID used here so they don't conflict | |
58 | -with any existing IDs on your system. Be sure to note the user ID and group ID | |
59 | -you use. | |
60 | - | |
61 | -``` | |
62 | -# groupadd -g 199 aya | |
63 | -# useradd -u 199 -g 199 -d /var/run -s /bin/false aya | |
64 | -``` | |
65 | - | |
66 | -Now you need to create some directories for Aya and fix their permissions. | |
67 | -These are the directories you decided on earlier in the prerequisites. These | |
68 | -should be owned by the user and group you just created, not by root. | |
69 | - | |
70 | -``` | |
71 | -# mkdir /var/log/aya | |
72 | -# chown -v aya:aya /var/log/aya | |
73 | -# chmod -v 750 /var/log/aya | |
74 | -# mkdir /var/www/gemini | |
75 | -# chown -v aya:aya /var/www/gemini | |
76 | -# chmod -v 755 /var/www/gemini | |
77 | -# chmod g+s /var/www/gemini | |
78 | -``` | |
79 | - | |
80 | -The final `chmod` (with the `g+s`) is to ensure that all files that get created | |
81 | -under your server root belong to the correct group. You also may want to adjust | |
82 | -the permissions of your server root to `775` (e.g. | |
83 | -`chmod -v 775 /var/www/gemini`) instead so that anyone within the group for | |
84 | -Aya can write files there. | |
85 | - | |
86 | -## Configuring Aya | |
87 | - | |
88 | -You now need to create a system-wide configuration file for Aya. When no | |
89 | -configuration file is specified on the command line, Aya will look for a config | |
90 | -file located at `/etc/aya/aya-config.yaml`. This will be your system-wide | |
91 | -configuration file. If you followed the directions in the previous section, you | |
92 | -should have a file named `/etc/aya/aya-config.yaml` that is ready for you to | |
93 | -edit. An example config might look like this: | |
94 | - | |
95 | -```yaml | |
96 | -# This is where you'll place your files that you want to serve. | |
97 | -server-root: /var/www/gemini | |
98 | - | |
99 | -# If you plan on having CGI scripts, you can place them in this directory. | |
100 | -# These should be executable by the user/group you created for Aya. | |
101 | -cgi-path: /var/www/gemini-cgi | |
102 | - | |
103 | -# This is the main log file for Aya. | |
104 | -log-file : /var/log/aya/aya.log | |
105 | - | |
106 | -# This is the file that Aya uses to log connections. Setting this to null | |
107 | -# disables logging of connections. This cannot be the same file as the | |
108 | -# main log-file above. | |
109 | -conn-log-file : aya-connections.log | |
110 | - | |
111 | -# This should match the user ID you created for Aya | |
112 | -uid: 199 | |
113 | - | |
114 | -# This should match the group ID you created for Aya | |
115 | -gid: 199 | |
116 | - | |
117 | -# Your SSL key and certificate chain should only be readable by root | |
118 | -# (e.g. chown root:root and chmod 400) | |
119 | -tls-key: /etc/ssl/private/aya.key | |
120 | -cert-chain: /etc/ssl/private/aya-chain.crt | |
121 | - | |
122 | -# The IP addresses/hostnames you want to listen for connections on. | |
123 | -listen: | |
124 | - - localhost | |
125 | - - 192.168.1.1 # obviously change this | |
126 | - | |
127 | -# Look at the sample-config.yaml for an explanation of these settings. | |
128 | -follow-symlinks: none | |
129 | -unknown-as-octet-stream: true | |
130 | -rate-limit: 0 | |
131 | -rate-limit-type: nongemini | |
132 | -footer: null | |
133 | -mime-file: null | |
134 | -cgi-extensions: [] | |
135 | -``` | |
136 | - | |
137 | -## Installing the Binary | |
138 | - | |
139 | -Copy your Aya binary somewhere where root can read and execute it. Be sure it's | |
140 | -owned by root. | |
141 | - | |
142 | -``` | |
143 | -# cp -v /path/to/your/downloaded/aya /usr/sbin/aya | |
144 | -# chown -v root:root /usr/sbin/aya | |
145 | -# chmod -v 755 /usr/sbin/aya | |
146 | -``` | |
147 | - | |
148 | -### Installing The Init Script | |
149 | - | |
150 | -An init script, `rc.aya`, comes with the Aya source code. This script is | |
151 | -intended to be used on a [Slackware Linux](http://www.slackware.com/) system, | |
152 | -but it should work with other Unix/Linux distributions as well. You may need to | |
153 | -adjust it to fit your needs, however (e.g., your system needs a different type | |
154 | -of init file, or you are not using the example values mentioned in the | |
155 | -Prerequisites section). | |
156 | - | |
157 | -On a Slackware-like system, you can copy this into `/etc/rc.d`, then modify a | |
158 | -few files so Aya is started and stopped automatically. | |
159 | - | |
160 | -``` | |
161 | -# cp -v /path/to/aya/sources/rc.aya /etc/rc.d | |
162 | -# chown -v root:root /etc/rc.d/rc.aya | |
163 | -# chmod a+x /etc/rc.d/rc.aya | |
164 | -``` | |
165 | - | |
166 | -To start Aya automatically at startup, edit `/etc/rc.d/rc.local` and place this | |
167 | -at the end: | |
168 | - | |
169 | -```bash | |
170 | -if [ -x /etc/rc.d/rc.aya ]; then | |
171 | - /etc/rc.d/rc.aya start | |
172 | -fi | |
173 | -``` | |
174 | - | |
175 | -Likewise, to stop Aya automatically at shutdown, edit | |
176 | -`/etc/rc.d/rc.local_shutdown` and place this at the end: | |
177 | - | |
178 | -```bash | |
179 | -if [ -x /etc/rc.d/rc.aya ]; then | |
180 | - /etc/rc.d/rc.aya stop | |
181 | -fi | |
182 | -``` | |
183 | - | |
184 | -Note that this `rc.aya` init script uses the `nohup` command to run Aya as a | |
185 | -daemon-like program. Any errors during startup can be found in the file pointed | |
186 | -to by the `OUTPUT_LOG` variable in `rc.aya` (default: | |
187 | -`/var/log/aya/aya-output.log`). When using this `rc.aya` script, the `log-file` | |
188 | -configuration setting is therefore redundant and can be set to `null`. | |
189 | - | |
190 | -Additionally, `rc.aya` uses a PID file to check/stop a running Aya instance. | |
191 | -This file is set using the `PID_FILE` variable in the script, and defaults to | |
192 | -`/var/run/aya.pid`. Wherever this pid file gets placed, it should be a | |
193 | -directory where the user that initially runs Aya can create the file. |
@@ -1,661 +0,0 @@ | ||
1 | - GNU AFFERO GENERAL PUBLIC LICENSE | |
2 | - Version 3, 19 November 2007 | |
3 | - | |
4 | - Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> | |
5 | - Everyone is permitted to copy and distribute verbatim copies | |
6 | - of this license document, but changing it is not allowed. | |
7 | - | |
8 | - Preamble | |
9 | - | |
10 | - The GNU Affero General Public License is a free, copyleft license for | |
11 | -software and other kinds of works, specifically designed to ensure | |
12 | -cooperation with the community in the case of network server software. | |
13 | - | |
14 | - The licenses for most software and other practical works are designed | |
15 | -to take away your freedom to share and change the works. By contrast, | |
16 | -our General Public Licenses are intended to guarantee your freedom to | |
17 | -share and change all versions of a program--to make sure it remains free | |
18 | -software for all its users. | |
19 | - | |
20 | - When we speak of free software, we are referring to freedom, not | |
21 | -price. Our General Public Licenses are designed to make sure that you | |
22 | -have the freedom to distribute copies of free software (and charge for | |
23 | -them if you wish), that you receive source code or can get it if you | |
24 | -want it, that you can change the software or use pieces of it in new | |
25 | -free programs, and that you know you can do these things. | |
26 | - | |
27 | - Developers that use our General Public Licenses protect your rights | |
28 | -with two steps: (1) assert copyright on the software, and (2) offer | |
29 | -you this License which gives you legal permission to copy, distribute | |
30 | -and/or modify the software. | |
31 | - | |
32 | - A secondary benefit of defending all users' freedom is that | |
33 | -improvements made in alternate versions of the program, if they | |
34 | -receive widespread use, become available for other developers to | |
35 | -incorporate. Many developers of free software are heartened and | |
36 | -encouraged by the resulting cooperation. However, in the case of | |
37 | -software used on network servers, this result may fail to come about. | |
38 | -The GNU General Public License permits making a modified version and | |
39 | -letting the public access it on a server without ever releasing its | |
40 | -source code to the public. | |
41 | - | |
42 | - The GNU Affero General Public License is designed specifically to | |
43 | -ensure that, in such cases, the modified source code becomes available | |
44 | -to the community. It requires the operator of a network server to | |
45 | -provide the source code of the modified version running there to the | |
46 | -users of that server. Therefore, public use of a modified version, on | |
47 | -a publicly accessible server, gives the public access to the source | |
48 | -code of the modified version. | |
49 | - | |
50 | - An older license, called the Affero General Public License and | |
51 | -published by Affero, was designed to accomplish similar goals. This is | |
52 | -a different license, not a version of the Affero GPL, but Affero has | |
53 | -released a new version of the Affero GPL which permits relicensing under | |
54 | -this license. | |
55 | - | |
56 | - The precise terms and conditions for copying, distribution and | |
57 | -modification follow. | |
58 | - | |
59 | - TERMS AND CONDITIONS | |
60 | - | |
61 | - 0. Definitions. | |
62 | - | |
63 | - "This License" refers to version 3 of the GNU Affero General Public License. | |
64 | - | |
65 | - "Copyright" also means copyright-like laws that apply to other kinds of | |
66 | -works, such as semiconductor masks. | |
67 | - | |
68 | - "The Program" refers to any copyrightable work licensed under this | |
69 | -License. Each licensee is addressed as "you". "Licensees" and | |
70 | -"recipients" may be individuals or organizations. | |
71 | - | |
72 | - To "modify" a work means to copy from or adapt all or part of the work | |
73 | -in a fashion requiring copyright permission, other than the making of an | |
74 | -exact copy. The resulting work is called a "modified version" of the | |
75 | -earlier work or a work "based on" the earlier work. | |
76 | - | |
77 | - A "covered work" means either the unmodified Program or a work based | |
78 | -on the Program. | |
79 | - | |
80 | - To "propagate" a work means to do anything with it that, without | |
81 | -permission, would make you directly or secondarily liable for | |
82 | -infringement under applicable copyright law, except executing it on a | |
83 | -computer or modifying a private copy. Propagation includes copying, | |
84 | -distribution (with or without modification), making available to the | |
85 | -public, and in some countries other activities as well. | |
86 | - | |
87 | - To "convey" a work means any kind of propagation that enables other | |
88 | -parties to make or receive copies. Mere interaction with a user through | |
89 | -a computer network, with no transfer of a copy, is not conveying. | |
90 | - | |
91 | - An interactive user interface displays "Appropriate Legal Notices" | |
92 | -to the extent that it includes a convenient and prominently visible | |
93 | -feature that (1) displays an appropriate copyright notice, and (2) | |
94 | -tells the user that there is no warranty for the work (except to the | |
95 | -extent that warranties are provided), that licensees may convey the | |
96 | -work under this License, and how to view a copy of this License. If | |
97 | -the interface presents a list of user commands or options, such as a | |
98 | -menu, a prominent item in the list meets this criterion. | |
99 | - | |
100 | - 1. Source Code. | |
101 | - | |
102 | - The "source code" for a work means the preferred form of the work | |
103 | -for making modifications to it. "Object code" means any non-source | |
104 | -form of a work. | |
105 | - | |
106 | - A "Standard Interface" means an interface that either is an official | |
107 | -standard defined by a recognized standards body, or, in the case of | |
108 | -interfaces specified for a particular programming language, one that | |
109 | -is widely used among developers working in that language. | |
110 | - | |
111 | - The "System Libraries" of an executable work include anything, other | |
112 | -than the work as a whole, that (a) is included in the normal form of | |
113 | -packaging a Major Component, but which is not part of that Major | |
114 | -Component, and (b) serves only to enable use of the work with that | |
115 | -Major Component, or to implement a Standard Interface for which an | |
116 | -implementation is available to the public in source code form. A | |
117 | -"Major Component", in this context, means a major essential component | |
118 | -(kernel, window system, and so on) of the specific operating system | |
119 | -(if any) on which the executable work runs, or a compiler used to | |
120 | -produce the work, or an object code interpreter used to run it. | |
121 | - | |
122 | - The "Corresponding Source" for a work in object code form means all | |
123 | -the source code needed to generate, install, and (for an executable | |
124 | -work) run the object code and to modify the work, including scripts to | |
125 | -control those activities. However, it does not include the work's | |
126 | -System Libraries, or general-purpose tools or generally available free | |
127 | -programs which are used unmodified in performing those activities but | |
128 | -which are not part of the work. For example, Corresponding Source | |
129 | -includes interface definition files associated with source files for | |
130 | -the work, and the source code for shared libraries and dynamically | |
131 | -linked subprograms that the work is specifically designed to require, | |
132 | -such as by intimate data communication or control flow between those | |
133 | -subprograms and other parts of the work. | |
134 | - | |
135 | - The Corresponding Source need not include anything that users | |
136 | -can regenerate automatically from other parts of the Corresponding | |
137 | -Source. | |
138 | - | |
139 | - The Corresponding Source for a work in source code form is that | |
140 | -same work. | |
141 | - | |
142 | - 2. Basic Permissions. | |
143 | - | |
144 | - All rights granted under this License are granted for the term of | |
145 | -copyright on the Program, and are irrevocable provided the stated | |
146 | -conditions are met. This License explicitly affirms your unlimited | |
147 | -permission to run the unmodified Program. The output from running a | |
148 | -covered work is covered by this License only if the output, given its | |
149 | -content, constitutes a covered work. This License acknowledges your | |
150 | -rights of fair use or other equivalent, as provided by copyright law. | |
151 | - | |
152 | - You may make, run and propagate covered works that you do not | |
153 | -convey, without conditions so long as your license otherwise remains | |
154 | -in force. You may convey covered works to others for the sole purpose | |
155 | -of having them make modifications exclusively for you, or provide you | |
156 | -with facilities for running those works, provided that you comply with | |
157 | -the terms of this License in conveying all material for which you do | |
158 | -not control copyright. Those thus making or running the covered works | |
159 | -for you must do so exclusively on your behalf, under your direction | |
160 | -and control, on terms that prohibit them from making any copies of | |
161 | -your copyrighted material outside their relationship with you. | |
162 | - | |
163 | - Conveying under any other circumstances is permitted solely under | |
164 | -the conditions stated below. Sublicensing is not allowed; section 10 | |
165 | -makes it unnecessary. | |
166 | - | |
167 | - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. | |
168 | - | |
169 | - No covered work shall be deemed part of an effective technological | |
170 | -measure under any applicable law fulfilling obligations under article | |
171 | -11 of the WIPO copyright treaty adopted on 20 December 1996, or | |
172 | -similar laws prohibiting or restricting circumvention of such | |
173 | -measures. | |
174 | - | |
175 | - When you convey a covered work, you waive any legal power to forbid | |
176 | -circumvention of technological measures to the extent such circumvention | |
177 | -is effected by exercising rights under this License with respect to | |
178 | -the covered work, and you disclaim any intention to limit operation or | |
179 | -modification of the work as a means of enforcing, against the work's | |
180 | -users, your or third parties' legal rights to forbid circumvention of | |
181 | -technological measures. | |
182 | - | |
183 | - 4. Conveying Verbatim Copies. | |
184 | - | |
185 | - You may convey verbatim copies of the Program's source code as you | |
186 | -receive it, in any medium, provided that you conspicuously and | |
187 | -appropriately publish on each copy an appropriate copyright notice; | |
188 | -keep intact all notices stating that this License and any | |
189 | -non-permissive terms added in accord with section 7 apply to the code; | |
190 | -keep intact all notices of the absence of any warranty; and give all | |
191 | -recipients a copy of this License along with the Program. | |
192 | - | |
193 | - You may charge any price or no price for each copy that you convey, | |
194 | -and you may offer support or warranty protection for a fee. | |
195 | - | |
196 | - 5. Conveying Modified Source Versions. | |
197 | - | |
198 | - You may convey a work based on the Program, or the modifications to | |
199 | -produce it from the Program, in the form of source code under the | |
200 | -terms of section 4, provided that you also meet all of these conditions: | |
201 | - | |
202 | - a) The work must carry prominent notices stating that you modified | |
203 | - it, and giving a relevant date. | |
204 | - | |
205 | - b) The work must carry prominent notices stating that it is | |
206 | - released under this License and any conditions added under section | |
207 | - 7. This requirement modifies the requirement in section 4 to | |
208 | - "keep intact all notices". | |
209 | - | |
210 | - c) You must license the entire work, as a whole, under this | |
211 | - License to anyone who comes into possession of a copy. This | |
212 | - License will therefore apply, along with any applicable section 7 | |
213 | - additional terms, to the whole of the work, and all its parts, | |
214 | - regardless of how they are packaged. This License gives no | |
215 | - permission to license the work in any other way, but it does not | |
216 | - invalidate such permission if you have separately received it. | |
217 | - | |
218 | - d) If the work has interactive user interfaces, each must display | |
219 | - Appropriate Legal Notices; however, if the Program has interactive | |
220 | - interfaces that do not display Appropriate Legal Notices, your | |
221 | - work need not make them do so. | |
222 | - | |
223 | - A compilation of a covered work with other separate and independent | |
224 | -works, which are not by their nature extensions of the covered work, | |
225 | -and which are not combined with it such as to form a larger program, | |
226 | -in or on a volume of a storage or distribution medium, is called an | |
227 | -"aggregate" if the compilation and its resulting copyright are not | |
228 | -used to limit the access or legal rights of the compilation's users | |
229 | -beyond what the individual works permit. Inclusion of a covered work | |
230 | -in an aggregate does not cause this License to apply to the other | |
231 | -parts of the aggregate. | |
232 | - | |
233 | - 6. Conveying Non-Source Forms. | |
234 | - | |
235 | - You may convey a covered work in object code form under the terms | |
236 | -of sections 4 and 5, provided that you also convey the | |
237 | -machine-readable Corresponding Source under the terms of this License, | |
238 | -in one of these ways: | |
239 | - | |
240 | - a) Convey the object code in, or embodied in, a physical product | |
241 | - (including a physical distribution medium), accompanied by the | |
242 | - Corresponding Source fixed on a durable physical medium | |
243 | - customarily used for software interchange. | |
244 | - | |
245 | - b) Convey the object code in, or embodied in, a physical product | |
246 | - (including a physical distribution medium), accompanied by a | |
247 | - written offer, valid for at least three years and valid for as | |
248 | - long as you offer spare parts or customer support for that product | |
249 | - model, to give anyone who possesses the object code either (1) a | |
250 | - copy of the Corresponding Source for all the software in the | |
251 | - product that is covered by this License, on a durable physical | |
252 | - medium customarily used for software interchange, for a price no | |
253 | - more than your reasonable cost of physically performing this | |
254 | - conveying of source, or (2) access to copy the | |
255 | - Corresponding Source from a network server at no charge. | |
256 | - | |
257 | - c) Convey individual copies of the object code with a copy of the | |
258 | - written offer to provide the Corresponding Source. This | |
259 | - alternative is allowed only occasionally and noncommercially, and | |
260 | - only if you received the object code with such an offer, in accord | |
261 | - with subsection 6b. | |
262 | - | |
263 | - d) Convey the object code by offering access from a designated | |
264 | - place (gratis or for a charge), and offer equivalent access to the | |
265 | - Corresponding Source in the same way through the same place at no | |
266 | - further charge. You need not require recipients to copy the | |
267 | - Corresponding Source along with the object code. If the place to | |
268 | - copy the object code is a network server, the Corresponding Source | |
269 | - may be on a different server (operated by you or a third party) | |
270 | - that supports equivalent copying facilities, provided you maintain | |
271 | - clear directions next to the object code saying where to find the | |
272 | - Corresponding Source. Regardless of what server hosts the | |
273 | - Corresponding Source, you remain obligated to ensure that it is | |
274 | - available for as long as needed to satisfy these requirements. | |
275 | - | |
276 | - e) Convey the object code using peer-to-peer transmission, provided | |
277 | - you inform other peers where the object code and Corresponding | |
278 | - Source of the work are being offered to the general public at no | |
279 | - charge under subsection 6d. | |
280 | - | |
281 | - A separable portion of the object code, whose source code is excluded | |
282 | -from the Corresponding Source as a System Library, need not be | |
283 | -included in conveying the object code work. | |
284 | - | |
285 | - A "User Product" is either (1) a "consumer product", which means any | |
286 | -tangible personal property which is normally used for personal, family, | |
287 | -or household purposes, or (2) anything designed or sold for incorporation | |
288 | -into a dwelling. In determining whether a product is a consumer product, | |
289 | -doubtful cases shall be resolved in favor of coverage. For a particular | |
290 | -product received by a particular user, "normally used" refers to a | |
291 | -typical or common use of that class of product, regardless of the status | |
292 | -of the particular user or of the way in which the particular user | |
293 | -actually uses, or expects or is expected to use, the product. A product | |
294 | -is a consumer product regardless of whether the product has substantial | |
295 | -commercial, industrial or non-consumer uses, unless such uses represent | |
296 | -the only significant mode of use of the product. | |
297 | - | |
298 | - "Installation Information" for a User Product means any methods, | |
299 | -procedures, authorization keys, or other information required to install | |
300 | -and execute modified versions of a covered work in that User Product from | |
301 | -a modified version of its Corresponding Source. The information must | |
302 | -suffice to ensure that the continued functioning of the modified object | |
303 | -code is in no case prevented or interfered with solely because | |
304 | -modification has been made. | |
305 | - | |
306 | - If you convey an object code work under this section in, or with, or | |
307 | -specifically for use in, a User Product, and the conveying occurs as | |
308 | -part of a transaction in which the right of possession and use of the | |
309 | -User Product is transferred to the recipient in perpetuity or for a | |
310 | -fixed term (regardless of how the transaction is characterized), the | |
311 | -Corresponding Source conveyed under this section must be accompanied | |
312 | -by the Installation Information. But this requirement does not apply | |
313 | -if neither you nor any third party retains the ability to install | |
314 | -modified object code on the User Product (for example, the work has | |
315 | -been installed in ROM). | |
316 | - | |
317 | - The requirement to provide Installation Information does not include a | |
318 | -requirement to continue to provide support service, warranty, or updates | |
319 | -for a work that has been modified or installed by the recipient, or for | |
320 | -the User Product in which it has been modified or installed. Access to a | |
321 | -network may be denied when the modification itself materially and | |
322 | -adversely affects the operation of the network or violates the rules and | |
323 | -protocols for communication across the network. | |
324 | - | |
325 | - Corresponding Source conveyed, and Installation Information provided, | |
326 | -in accord with this section must be in a format that is publicly | |
327 | -documented (and with an implementation available to the public in | |
328 | -source code form), and must require no special password or key for | |
329 | -unpacking, reading or copying. | |
330 | - | |
331 | - 7. Additional Terms. | |
332 | - | |
333 | - "Additional permissions" are terms that supplement the terms of this | |
334 | -License by making exceptions from one or more of its conditions. | |
335 | -Additional permissions that are applicable to the entire Program shall | |
336 | -be treated as though they were included in this License, to the extent | |
337 | -that they are valid under applicable law. If additional permissions | |
338 | -apply only to part of the Program, that part may be used separately | |
339 | -under those permissions, but the entire Program remains governed by | |
340 | -this License without regard to the additional permissions. | |
341 | - | |
342 | - When you convey a copy of a covered work, you may at your option | |
343 | -remove any additional permissions from that copy, or from any part of | |
344 | -it. (Additional permissions may be written to require their own | |
345 | -removal in certain cases when you modify the work.) You may place | |
346 | -additional permissions on material, added by you to a covered work, | |
347 | -for which you have or can give appropriate copyright permission. | |
348 | - | |
349 | - Notwithstanding any other provision of this License, for material you | |
350 | -add to a covered work, you may (if authorized by the copyright holders of | |
351 | -that material) supplement the terms of this License with terms: | |
352 | - | |
353 | - a) Disclaiming warranty or limiting liability differently from the | |
354 | - terms of sections 15 and 16 of this License; or | |
355 | - | |
356 | - b) Requiring preservation of specified reasonable legal notices or | |
357 | - author attributions in that material or in the Appropriate Legal | |
358 | - Notices displayed by works containing it; or | |
359 | - | |
360 | - c) Prohibiting misrepresentation of the origin of that material, or | |
361 | - requiring that modified versions of such material be marked in | |
362 | - reasonable ways as different from the original version; or | |
363 | - | |
364 | - d) Limiting the use for publicity purposes of names of licensors or | |
365 | - authors of the material; or | |
366 | - | |
367 | - e) Declining to grant rights under trademark law for use of some | |
368 | - trade names, trademarks, or service marks; or | |
369 | - | |
370 | - f) Requiring indemnification of licensors and authors of that | |
371 | - material by anyone who conveys the material (or modified versions of | |
372 | - it) with contractual assumptions of liability to the recipient, for | |
373 | - any liability that these contractual assumptions directly impose on | |
374 | - those licensors and authors. | |
375 | - | |
376 | - All other non-permissive additional terms are considered "further | |
377 | -restrictions" within the meaning of section 10. If the Program as you | |
378 | -received it, or any part of it, contains a notice stating that it is | |
379 | -governed by this License along with a term that is a further | |
380 | -restriction, you may remove that term. If a license document contains | |
381 | -a further restriction but permits relicensing or conveying under this | |
382 | -License, you may add to a covered work material governed by the terms | |
383 | -of that license document, provided that the further restriction does | |
384 | -not survive such relicensing or conveying. | |
385 | - | |
386 | - If you add terms to a covered work in accord with this section, you | |
387 | -must place, in the relevant source files, a statement of the | |
388 | -additional terms that apply to those files, or a notice indicating | |
389 | -where to find the applicable terms. | |
390 | - | |
391 | - Additional terms, permissive or non-permissive, may be stated in the | |
392 | -form of a separately written license, or stated as exceptions; | |
393 | -the above requirements apply either way. | |
394 | - | |
395 | - 8. Termination. | |
396 | - | |
397 | - You may not propagate or modify a covered work except as expressly | |
398 | -provided under this License. Any attempt otherwise to propagate or | |
399 | -modify it is void, and will automatically terminate your rights under | |
400 | -this License (including any patent licenses granted under the third | |
401 | -paragraph of section 11). | |
402 | - | |
403 | - However, if you cease all violation of this License, then your | |
404 | -license from a particular copyright holder is reinstated (a) | |
405 | -provisionally, unless and until the copyright holder explicitly and | |
406 | -finally terminates your license, and (b) permanently, if the copyright | |
407 | -holder fails to notify you of the violation by some reasonable means | |
408 | -prior to 60 days after the cessation. | |
409 | - | |
410 | - Moreover, your license from a particular copyright holder is | |
411 | -reinstated permanently if the copyright holder notifies you of the | |
412 | -violation by some reasonable means, this is the first time you have | |
413 | -received notice of violation of this License (for any work) from that | |
414 | -copyright holder, and you cure the violation prior to 30 days after | |
415 | -your receipt of the notice. | |
416 | - | |
417 | - Termination of your rights under this section does not terminate the | |
418 | -licenses of parties who have received copies or rights from you under | |
419 | -this License. If your rights have been terminated and not permanently | |
420 | -reinstated, you do not qualify to receive new licenses for the same | |
421 | -material under section 10. | |
422 | - | |
423 | - 9. Acceptance Not Required for Having Copies. | |
424 | - | |
425 | - You are not required to accept this License in order to receive or | |
426 | -run a copy of the Program. Ancillary propagation of a covered work | |
427 | -occurring solely as a consequence of using peer-to-peer transmission | |
428 | -to receive a copy likewise does not require acceptance. However, | |
429 | -nothing other than this License grants you permission to propagate or | |
430 | -modify any covered work. These actions infringe copyright if you do | |
431 | -not accept this License. Therefore, by modifying or propagating a | |
432 | -covered work, you indicate your acceptance of this License to do so. | |
433 | - | |
434 | - 10. Automatic Licensing of Downstream Recipients. | |
435 | - | |
436 | - Each time you convey a covered work, the recipient automatically | |
437 | -receives a license from the original licensors, to run, modify and | |
438 | -propagate that work, subject to this License. You are not responsible | |
439 | -for enforcing compliance by third parties with this License. | |
440 | - | |
441 | - An "entity transaction" is a transaction transferring control of an | |
442 | -organization, or substantially all assets of one, or subdividing an | |
443 | -organization, or merging organizations. If propagation of a covered | |
444 | -work results from an entity transaction, each party to that | |
445 | -transaction who receives a copy of the work also receives whatever | |
446 | -licenses to the work the party's predecessor in interest had or could | |
447 | -give under the previous paragraph, plus a right to possession of the | |
448 | -Corresponding Source of the work from the predecessor in interest, if | |
449 | -the predecessor has it or can get it with reasonable efforts. | |
450 | - | |
451 | - You may not impose any further restrictions on the exercise of the | |
452 | -rights granted or affirmed under this License. For example, you may | |
453 | -not impose a license fee, royalty, or other charge for exercise of | |
454 | -rights granted under this License, and you may not initiate litigation | |
455 | -(including a cross-claim or counterclaim in a lawsuit) alleging that | |
456 | -any patent claim is infringed by making, using, selling, offering for | |
457 | -sale, or importing the Program or any portion of it. | |
458 | - | |
459 | - 11. Patents. | |
460 | - | |
461 | - A "contributor" is a copyright holder who authorizes use under this | |
462 | -License of the Program or a work on which the Program is based. The | |
463 | -work thus licensed is called the contributor's "contributor version". | |
464 | - | |
465 | - A contributor's "essential patent claims" are all patent claims | |
466 | -owned or controlled by the contributor, whether already acquired or | |
467 | -hereafter acquired, that would be infringed by some manner, permitted | |
468 | -by this License, of making, using, or selling its contributor version, | |
469 | -but do not include claims that would be infringed only as a | |
470 | -consequence of further modification of the contributor version. For | |
471 | -purposes of this definition, "control" includes the right to grant | |
472 | -patent sublicenses in a manner consistent with the requirements of | |
473 | -this License. | |
474 | - | |
475 | - Each contributor grants you a non-exclusive, worldwide, royalty-free | |
476 | -patent license under the contributor's essential patent claims, to | |
477 | -make, use, sell, offer for sale, import and otherwise run, modify and | |
478 | -propagate the contents of its contributor version. | |
479 | - | |
480 | - In the following three paragraphs, a "patent license" is any express | |
481 | -agreement or commitment, however denominated, not to enforce a patent | |
482 | -(such as an express permission to practice a patent or covenant not to | |
483 | -sue for patent infringement). To "grant" such a patent license to a | |
484 | -party means to make such an agreement or commitment not to enforce a | |
485 | -patent against the party. | |
486 | - | |
487 | - If you convey a covered work, knowingly relying on a patent license, | |
488 | -and the Corresponding Source of the work is not available for anyone | |
489 | -to copy, free of charge and under the terms of this License, through a | |
490 | -publicly available network server or other readily accessible means, | |
491 | -then you must either (1) cause the Corresponding Source to be so | |
492 | -available, or (2) arrange to deprive yourself of the benefit of the | |
493 | -patent license for this particular work, or (3) arrange, in a manner | |
494 | -consistent with the requirements of this License, to extend the patent | |
495 | -license to downstream recipients. "Knowingly relying" means you have | |
496 | -actual knowledge that, but for the patent license, your conveying the | |
497 | -covered work in a country, or your recipient's use of the covered work | |
498 | -in a country, would infringe one or more identifiable patents in that | |
499 | -country that you have reason to believe are valid. | |
500 | - | |
501 | - If, pursuant to or in connection with a single transaction or | |
502 | -arrangement, you convey, or propagate by procuring conveyance of, a | |
503 | -covered work, and grant a patent license to some of the parties | |
504 | -receiving the covered work authorizing them to use, propagate, modify | |
505 | -or convey a specific copy of the covered work, then the patent license | |
506 | -you grant is automatically extended to all recipients of the covered | |
507 | -work and works based on it. | |
508 | - | |
509 | - A patent license is "discriminatory" if it does not include within | |
510 | -the scope of its coverage, prohibits the exercise of, or is | |
511 | -conditioned on the non-exercise of one or more of the rights that are | |
512 | -specifically granted under this License. You may not convey a covered | |
513 | -work if you are a party to an arrangement with a third party that is | |
514 | -in the business of distributing software, under which you make payment | |
515 | -to the third party based on the extent of your activity of conveying | |
516 | -the work, and under which the third party grants, to any of the | |
517 | -parties who would receive the covered work from you, a discriminatory | |
518 | -patent license (a) in connection with copies of the covered work | |
519 | -conveyed by you (or copies made from those copies), or (b) primarily | |
520 | -for and in connection with specific products or compilations that | |
521 | -contain the covered work, unless you entered into that arrangement, | |
522 | -or that patent license was granted, prior to 28 March 2007. | |
523 | - | |
524 | - Nothing in this License shall be construed as excluding or limiting | |
525 | -any implied license or other defenses to infringement that may | |
526 | -otherwise be available to you under applicable patent law. | |
527 | - | |
528 | - 12. No Surrender of Others' Freedom. | |
529 | - | |
530 | - If conditions are imposed on you (whether by court order, agreement or | |
531 | -otherwise) that contradict the conditions of this License, they do not | |
532 | -excuse you from the conditions of this License. If you cannot convey a | |
533 | -covered work so as to satisfy simultaneously your obligations under this | |
534 | -License and any other pertinent obligations, then as a consequence you may | |
535 | -not convey it at all. For example, if you agree to terms that obligate you | |
536 | -to collect a royalty for further conveying from those to whom you convey | |
537 | -the Program, the only way you could satisfy both those terms and this | |
538 | -License would be to refrain entirely from conveying the Program. | |
539 | - | |
540 | - 13. Remote Network Interaction; Use with the GNU General Public License. | |
541 | - | |
542 | - Notwithstanding any other provision of this License, if you modify the | |
543 | -Program, your modified version must prominently offer all users | |
544 | -interacting with it remotely through a computer network (if your version | |
545 | -supports such interaction) an opportunity to receive the Corresponding | |
546 | -Source of your version by providing access to the Corresponding Source | |
547 | -from a network server at no charge, through some standard or customary | |
548 | -means of facilitating copying of software. This Corresponding Source | |
549 | -shall include the Corresponding Source for any work covered by version 3 | |
550 | -of the GNU General Public License that is incorporated pursuant to the | |
551 | -following paragraph. | |
552 | - | |
553 | - Notwithstanding any other provision of this License, you have | |
554 | -permission to link or combine any covered work with a work licensed | |
555 | -under version 3 of the GNU General Public License into a single | |
556 | -combined work, and to convey the resulting work. The terms of this | |
557 | -License will continue to apply to the part which is the covered work, | |
558 | -but the work with which it is combined will remain governed by version | |
559 | -3 of the GNU General Public License. | |
560 | - | |
561 | - 14. Revised Versions of this License. | |
562 | - | |
563 | - The Free Software Foundation may publish revised and/or new versions of | |
564 | -the GNU Affero General Public License from time to time. Such new versions | |
565 | -will be similar in spirit to the present version, but may differ in detail to | |
566 | -address new problems or concerns. | |
567 | - | |
568 | - Each version is given a distinguishing version number. If the | |
569 | -Program specifies that a certain numbered version of the GNU Affero General | |
570 | -Public License "or any later version" applies to it, you have the | |
571 | -option of following the terms and conditions either of that numbered | |
572 | -version or of any later version published by the Free Software | |
573 | -Foundation. If the Program does not specify a version number of the | |
574 | -GNU Affero General Public License, you may choose any version ever published | |
575 | -by the Free Software Foundation. | |
576 | - | |
577 | - If the Program specifies that a proxy can decide which future | |
578 | -versions of the GNU Affero General Public License can be used, that proxy's | |
579 | -public statement of acceptance of a version permanently authorizes you | |
580 | -to choose that version for the Program. | |
581 | - | |
582 | - Later license versions may give you additional or different | |
583 | -permissions. However, no additional obligations are imposed on any | |
584 | -author or copyright holder as a result of your choosing to follow a | |
585 | -later version. | |
586 | - | |
587 | - 15. Disclaimer of Warranty. | |
588 | - | |
589 | - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | |
590 | -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | |
591 | -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | |
592 | -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | |
593 | -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
594 | -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | |
595 | -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | |
596 | -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |
597 | - | |
598 | - 16. Limitation of Liability. | |
599 | - | |
600 | - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
601 | -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | |
602 | -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | |
603 | -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | |
604 | -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | |
605 | -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | |
606 | -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | |
607 | -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | |
608 | -SUCH DAMAGES. | |
609 | - | |
610 | - 17. Interpretation of Sections 15 and 16. | |
611 | - | |
612 | - If the disclaimer of warranty and limitation of liability provided | |
613 | -above cannot be given local legal effect according to their terms, | |
614 | -reviewing courts shall apply local law that most closely approximates | |
615 | -an absolute waiver of all civil liability in connection with the | |
616 | -Program, unless a warranty or assumption of liability accompanies a | |
617 | -copy of the Program in return for a fee. | |
618 | - | |
619 | - END OF TERMS AND CONDITIONS | |
620 | - | |
621 | - How to Apply These Terms to Your New Programs | |
622 | - | |
623 | - If you develop a new program, and you want it to be of the greatest | |
624 | -possible use to the public, the best way to achieve this is to make it | |
625 | -free software which everyone can redistribute and change under these terms. | |
626 | - | |
627 | - To do so, attach the following notices to the program. It is safest | |
628 | -to attach them to the start of each source file to most effectively | |
629 | -state the exclusion of warranty; and each file should have at least | |
630 | -the "copyright" line and a pointer to where the full notice is found. | |
631 | - | |
632 | - <one line to give the program's name and a brief idea of what it does.> | |
633 | - Copyright (C) <year> <name of author> | |
634 | - | |
635 | - This program is free software: you can redistribute it and/or modify | |
636 | - it under the terms of the GNU Affero General Public License as published by | |
637 | - the Free Software Foundation, either version 3 of the License, or | |
638 | - (at your option) any later version. | |
639 | - | |
640 | - This program is distributed in the hope that it will be useful, | |
641 | - but WITHOUT ANY WARRANTY; without even the implied warranty of | |
642 | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
643 | - GNU Affero General Public License for more details. | |
644 | - | |
645 | - You should have received a copy of the GNU Affero General Public License | |
646 | - along with this program. If not, see <https://www.gnu.org/licenses/>. | |
647 | - | |
648 | -Also add information on how to contact you by electronic and paper mail. | |
649 | - | |
650 | - If your software can interact with users remotely through a computer | |
651 | -network, you should also make sure that it provides a way for users to | |
652 | -get its source. For example, if your program is a web application, its | |
653 | -interface could display a "Source" link that leads users to an archive | |
654 | -of the code. There are many ways you could offer source, and different | |
655 | -solutions will be better for different programs; see section 13 for the | |
656 | -specific requirements. | |
657 | - | |
658 | - You should also get your employer (if you work as a programmer) or school, | |
659 | -if any, to sign a "copyright disclaimer" for the program, if necessary. | |
660 | -For more information on this, and how to apply and follow the GNU AGPL, see | |
661 | -<https://www.gnu.org/licenses/>. |
@@ -1,32 +0,0 @@ | ||
1 | -Aya v0.3.0 | |
2 | -========== | |
3 | - | |
4 | -Changes since v0.2.0: | |
5 | ---------------------- | |
6 | - | |
7 | -Features: | |
8 | -* Fixed changing the real/effective UID and GID at startup. | |
9 | -* The SSL key and certificate chain can now be owned by a different user than | |
10 | - the UID/GID that Aya changes to. | |
11 | -* Added rc.aya sample init script. | |
12 | -* Connection logging now works as intended. | |
13 | -* The `cgi-extensions` configuration key can no longer be an empty list. | |
14 | -* Added the `--dump-config` command line option to dump an example | |
15 | - configuration. | |
16 | -* The default configuration file is now `/etc/aya/aya-config.yaml`. | |
17 | -* Added INSTALL.md that contains instructions for installing Aya system-wide. | |
18 | - | |
19 | -Changes since v0.1.2: | |
20 | ---------------------- | |
21 | - | |
22 | -* Aya now uses the RemiGemini library. | |
23 | -* Aya now uses the IdleGC library. | |
24 | - | |
25 | -Changes since v0.1.1: | |
26 | ---------------------- | |
27 | - | |
28 | -Features: | |
29 | -* Aya can now change her real and effective UID and GID on startup. See | |
30 | - sample-config.yml for an example of how to do this. | |
31 | -* The new configuration variable `footer` can be used to append a footer onto | |
32 | - each Gemtext page that is served. |
@@ -1,70 +1,3 @@ | ||
1 | 1 | # Aya Gemini Server |
2 | 2 | |
3 | -Aya is a simple | |
4 | -[Gemini](https://portal.mozz.us/gemini/gemini.circumlunar.space/) server written | |
5 | -in [Crystal](https://crystal-lang.org/) and released under the | |
6 | -[GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.html). | |
7 | - | |
8 | -Wanna support Remilia? [Buy me a coffee on Ko-Fi](https://ko-fi.com/L4L614QNC), | |
9 | -or support me through Liberapay. | |
10 | - | |
11 | -<a href='https://ko-fi.com/L4L614QNC' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi2.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a> | |
12 | -<a href="https://liberapay.com/RemiliaScarlet/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a> | |
13 | - | |
14 | -## How do I get set up? | |
15 | - | |
16 | -You will need [Mercurial](https://www.mercurial-scm.org/) installed to clone | |
17 | -this repository. | |
18 | - | |
19 | -You will need [Fossil](https://fossil-scm.org/) installed to clone some of the | |
20 | -dependencies for this repository. You will also need Shards v0.17.1 or later. | |
21 | -If you have an earlier version of Shards, you will need to to build the [latest | |
22 | -version](https://github.com/crystal-lang/shards/) manually. | |
23 | - | |
24 | -1. Clone this repository | |
25 | -2. Run `shards` (or `shards --release` for a release build). The binary will be | |
26 | - in the `bin/` directory. | |
27 | -3. Create a configuration file by copying `sample-config.yml` and editing the | |
28 | - copy. Note that Aya will automatically attempt load a file named | |
29 | - `/etc/aya/aya-config.yaml`, otherwise you will need to use the `--config` | |
30 | - parameter. | |
31 | -4. Start Aya. | |
32 | - | |
33 | -If you wish to install Aya in a system-wide way, check the `INSTALL.md` in the | |
34 | -repository root. | |
35 | - | |
36 | -## Development | |
37 | - | |
38 | -### Style info | |
39 | - | |
40 | -I use a somewhat non-standard style for my code. | |
41 | - | |
42 | -- Keep lines 118 characters or shorter. Obviously sometimes you can't, but | |
43 | - please try. Use 80 or 115 characters for Markdown files, though. | |
44 | -- Please use pascalCase for variable and method names. Use CamelCase for type | |
45 | - names. Use UPPER_SNAKE_CASE for constants. | |
46 | -- Put parentheses around method parameters, except for these methods: `puts`, | |
47 | - `pp`, `p`, `raise`, `sleep`, `spawn`, `loop`, and `exit`. | |
48 | -- Always the full `do |foo|...end` syntax with blocks, except when it's all on | |
49 | - one line or an anonymous function, then use { and } or the normal `do | |
50 | - |foo|...end`. | |
51 | -- The type name for exceptions end with Error. For example, `ExternalProgramError`. | |
52 | - | |
53 | -## How do I contribute? | |
54 | - | |
55 | -1. Go to https://osdn.net/users/yukiraven/pf/aya/ and clone the Mercurial repository. | |
56 | -2. Create a new branch for your feature. | |
57 | -3. Push locally to the new branch | |
58 | -4. Create a ticket. | |
59 | - | |
60 | -## Contributors | |
61 | - | |
62 | -* Remilia Scarlet - creator and maintainer | |
63 | - * Homepage: [https://remilia.sdf.org/](https://remilia.sdf.org/) | |
64 | - * Gemini: [gemini://nanako.mooo.com/](gemini://nanako.mooo.com/) | |
65 | - * Mastodon: [@MistressRemilia@social.sdf.org](https://social.sdf.org/@MistressRemilia) | |
66 | - * Email: zremiliaz@postzeoz.jpz My real address does not contain Z's | |
67 | - | |
68 | -## Links and Licenses | |
69 | - | |
70 | -Aya is under the [GNU Affero General Public License version 3](https://www.gnu.org/licenses/agpl-3.0.html). | |
3 | +**MOVED!** Please visit https://nanako.mooo.com/fossil/aya/ for the latest code. |
@@ -1,45 +0,0 @@ | ||
1 | -# Aya CGI Interface v0.1.0 | |
2 | - | |
3 | -Aya can be configured to understand certain file extensions as CGI scripts. | |
4 | -This is done in the configuration file using the `cgi-extensions` key. The | |
5 | -protocol for handling these (aka, what you're reading now) is deliberately | |
6 | -simple and roughly based on usual CGI 1.1 spec. | |
7 | - | |
8 | -When a client sends a request and the path component has one of the CGI | |
9 | -extensions at the very end, Aya will attempt to execute that file. If the file | |
10 | -does not exist, is not executable, or exits with an exit code of anything other | |
11 | -than 0, a `40 Temporary Failure` response is sent. Otherwise its output is sent | |
12 | -verbatim to the requesting client. | |
13 | - | |
14 | -The CGI script's environment will have various variables set that are filled | |
15 | -with information from the client. The `PATH` environment variable is also set | |
16 | -strictly according to the `cgi-path` key in the configuration file. The | |
17 | -server's `PATH` is not inherited, and no other environment variables except | |
18 | -those listed below exist for the CGI process. | |
19 | - | |
20 | -## Environment Variables | |
21 | - | |
22 | -* **DOCUMENT_ROOT**: The server root path, equivalent to the `server-root` key in the config file. | |
23 | -* **GATEWAY_INTERFACE**: The name and version of the Aya CGI Interface. This | |
24 | - should be `ACGI`, a space, and then a syumantic version. | |
25 | -* **PATH_INFO**: The path component of the URI | |
26 | -* **PATH_TRANSLATED**: The path to the CGI script as the server sees it. | |
27 | -* **SCRIPT_FILENAME**: The filename of the CGI script | |
28 | -* **QUERY_STRING**: The query component of the URI. | |
29 | -* **REQUEST_FRAGMENT**: The request component of the URI. | |
30 | -* **SERVER_HOST**: The host component of the URI. | |
31 | -* **SERVER_PORT**: The port component of the URI. The `listen-port` value will | |
32 | - be inserted here if the URI did not have a port specified. | |
33 | -* **PATH**: Same as usual, the `PATH` as understood by the shell. | |
34 | - | |
35 | -## Standard Input, Standard Output, and Standard Error | |
36 | - | |
37 | -Nothing is passed to the CGI process on standard input. | |
38 | - | |
39 | -The CGI process is expected to produce a valid Gemini response header (and | |
40 | -corresponding body, if applicable) on standard output. This will be sent | |
41 | -verbatim over the socket back to the requesting client. | |
42 | - | |
43 | -If the CGI script encounters an error, it can be printed on standard error. Any | |
44 | -output on this stream will be logged by Aya to its own standard error, as well | |
45 | -as any configured log file. |
@@ -1,126 +0,0 @@ | ||
1 | -#!/bin/bash | |
2 | - | |
3 | -#### This file is part of Aya. | |
4 | -#### | |
5 | -#### Aya is free software: you can redistribute it and/or modify it under the | |
6 | -#### terms of the GNU Affero General Public License as published by the Free | |
7 | -#### Software Foundation, either version 3 of the License, or (at your option) | |
8 | -#### any later version. | |
9 | -#### | |
10 | -#### This program is distributed in the hope that it will be useful, but WITHOUT | |
11 | -#### ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | -#### FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public | |
13 | -#### License for more details. | |
14 | -#### | |
15 | -#### You should have received a copy of the GNU Affero General Public License | |
16 | -#### along with this program. If not, see <https://www.gnu.org/licenses/>. | |
17 | - | |
18 | -# Start/stop/restart the Aya daemon: | |
19 | - | |
20 | -PATH=/sbin:/bin:/usr/sbin:/usr/bin | |
21 | -PROGRAM=/usr/sbin/aya | |
22 | -PID_FILE=/var/run/aya.pid | |
23 | -OUTPUT_LOG=/var/log/aya/aya-output.log | |
24 | - | |
25 | -# Starts Aya if it isn't yet running. | |
26 | -aya_start() { | |
27 | - if [ -f $PID_FILE ]; then | |
28 | - echo "Aya is already running" | |
29 | - else | |
30 | - echo "Starting Aya: nohup $PROGRAM --pid $PID_FILE > $OUTPUT_LOG" | |
31 | - nohup $PROGRAM --pid $PID_FILE > $OUTPUT_LOG | |
32 | - | |
33 | - sleep 2 | |
34 | - if [ $? -ne 0 ]; then | |
35 | - echo "Aya failed to start, check $OUTPUT_LOG for details" | |
36 | - return 1 | |
37 | - fi | |
38 | - | |
39 | - if [ ! -f $PID_FILE ]; then | |
40 | - echo "Aya may have failed to start (no PID file was created)" | |
41 | - echo "Check $OUTPUT_LOG for details." | |
42 | - return 1 | |
43 | - fi | |
44 | - | |
45 | - echo "Aya has been started with PID $(cat $PID_FILE)" | |
46 | - fi | |
47 | -} | |
48 | - | |
49 | -# Checks if Aya is running. If it is, this sets $? to 0, otherwise it sets it | |
50 | -# to 1. | |
51 | -aya_status_quiet() { | |
52 | - if [ -f $PID_FILE ]; then | |
53 | - return 0 | |
54 | - else | |
55 | - return 1 | |
56 | - fi | |
57 | -} | |
58 | - | |
59 | -# Checks if Aya is running and prints a message. If it is, this sets $? to 0, | |
60 | -# otherwise it sets it to 1. | |
61 | -aya_status() { | |
62 | - if [ -f $PID_FILE ]; then | |
63 | - local PID=$(cat $PID_FILE) | |
64 | - echo "Aya is running with PID $PID" | |
65 | - return 0 | |
66 | - else | |
67 | - echo "Aya is not running" | |
68 | - return 1 | |
69 | - fi | |
70 | -} | |
71 | - | |
72 | -# Stops Aya if it's running. | |
73 | -aya_stop() { | |
74 | - if [ -f $PID_FILE ]; then | |
75 | - echo -n "Stopping Aya: " | |
76 | - local PID=$(cat $PID_FILE) | |
77 | - kill $PID | |
78 | - if [ $? -ne 0 ]; then | |
79 | - echo "Failed" | |
80 | - echo "Could not stop Aya (stale PID?)" | |
81 | - else | |
82 | - rm -f $PID_FILE | |
83 | - echo "Stopped" | |
84 | - fi | |
85 | - else | |
86 | - echo "Aya does not seem to be running" | |
87 | - fi | |
88 | -} | |
89 | - | |
90 | -# Restarts aya. | |
91 | -aya_restart() { | |
92 | - aya_stop | |
93 | - sleep 2 | |
94 | - aya_start | |
95 | -} | |
96 | - | |
97 | -### | |
98 | -### Main entry point | |
99 | -### | |
100 | - | |
101 | -case "$1" in | |
102 | - 'start') | |
103 | - aya_status_quiet | |
104 | - if [ $? -eq 1 ]; then | |
105 | - aya_start | |
106 | - else | |
107 | - echo "Aya is already running." | |
108 | - fi | |
109 | - ;; | |
110 | - | |
111 | - 'stop') | |
112 | - aya_stop | |
113 | - ;; | |
114 | - | |
115 | - 'restart') | |
116 | - aya_restart | |
117 | - ;; | |
118 | - | |
119 | - 'status') | |
120 | - aya_status | |
121 | - ;; | |
122 | - | |
123 | - *) | |
124 | - echo "usage $0 start|stop|status|restart" | |
125 | - ;; | |
126 | -esac |
@@ -1,103 +0,0 @@ | ||
1 | -#### | |
2 | -#### Sample configuration file for the Aya Gemini Server. | |
3 | -#### | |
4 | -#### You can get a much more minimal sample configuration by running | |
5 | -#### `aya --dump-config`, then modifying it with appropriate values. | |
6 | -#### | |
7 | - | |
8 | -# Where to look for files to serve | |
9 | -server-root: /var/gemini-root | |
10 | - | |
11 | -# When a CGI script is executed, this string will be set as the PATH environment | |
12 | -# variable. The default is an empty string (no PATH). | |
13 | -cgi-path: "" | |
14 | - | |
15 | -# Files with these extensions in the server root will be treated as CGI programs | |
16 | -# to execute. Anything sent to standard output by these programs will be served | |
17 | -# as a response body. Output should include the response header and any | |
18 | -# applicable body. This cannot be an empty list. | |
19 | -# | |
20 | -# Be sure to include the dot (.) in the extension name. | |
21 | -cgi-extensions: | |
22 | - - .cgi | |
23 | - | |
24 | -# The port to listen on for connections. If this is not present, the default is | |
25 | -# 1965. | |
26 | -#listen-port: 1965 | |
27 | - | |
28 | -# When this is a non-empty string, all non-connection related messages will be | |
29 | -# logged to this file as well as standard output/standard error. | |
30 | -log-file: aya.log | |
31 | - | |
32 | -# When this is a non-empty string, connections will be logged to this file. | |
33 | -# This cannot be the same file as specified in the log-file key. | |
34 | -conn-log-file: aya-connections.log | |
35 | - | |
36 | -# When this is present and not null, Aya will change her the real and effective | |
37 | -# UID during startup. If this is null (the default), Aya will use the UID of | |
38 | -# the user who launched the process. | |
39 | -uid: null | |
40 | - | |
41 | -# When this is present and not null, Aya will change her the real and effective | |
42 | -# GID during startup. If this is null (the default), Aya will use the GID of | |
43 | -# the user who launched the process. | |
44 | -gid: null | |
45 | - | |
46 | -# If 'none', then symlinks are never followed when serving a request. When | |
47 | -# 'all', then all symlinks will be followed (this is dangerous) | |
48 | -follow-symlinks: none | |
49 | - | |
50 | -# Where to find a mime.types file for MIME media type information. If this is | |
51 | -# null (the default), an attempt will be made to find a suitable default. | |
52 | -# | |
53 | -# Note that according to https://crystal-lang.org/api/1.0.0/MIME.html, these | |
54 | -# will be searched first, otherwise the types defined in MIME::DFEFAULT_TYPES is | |
55 | -# used. | |
56 | -# /etc/mime.types | |
57 | -# /etc/httpd/mime.types # Mac OS X | |
58 | -# /etc/httpd/conf/mime.types # Apache | |
59 | -# /etc/apache/mime.types # Apache 1 | |
60 | -# /etc/apache2/mime.types # Apache 2 | |
61 | -# /usr/local/etc/httpd/conf/mime.types | |
62 | -# /usr/local/lib/netscape/mime.types | |
63 | -# /usr/local/etc/httpd/conf/mime.types # Apache 1.2 | |
64 | -# /usr/local/etc/mime.types # FreeBSD | |
65 | -# /usr/share/misc/mime.types # OpenBSD | |
66 | -mime-file: null | |
67 | -#mime-file: /path/to/mime.types | |
68 | - | |
69 | -# Dictates how files of unknown MIME media types are served. If this is 'true', | |
70 | -# files of unknown types are served as 'application/octet-stream'. Otherwise | |
71 | -# they are not served, error type 40 is sent, and an error is printed on the | |
72 | -# console. | |
73 | -unknown-as-octet-stream: true | |
74 | - | |
75 | -# The location of the TLS certificate key. | |
76 | -tls-key: /path/to/your.key | |
77 | - | |
78 | -# The location of the certificate chain | |
79 | -cert-chain: /path/to/chain.crt | |
80 | - | |
81 | -# When this is greater than zero, this will enable rate limiting of connections. | |
82 | -# This value is in kilobytes, so 60 = 60KiB/sec. Setting this to 0 disables | |
83 | -# rate limiting. | |
84 | -rate-limit: 0 | |
85 | - | |
86 | -# If this is not an empty string, this tells Aya to append a footer onto the end | |
87 | -# of every Gemtext page served. | |
88 | -footer: | | |
89 | - ``` Footer telling the user the page was served with Aya (https://osdn.net/users/yukiraven/pf/aya/) | |
90 | - --------- | |
91 | - Page served by Aya https://osdn.net/users/yukiraven/pf/aya/ | |
92 | - Aya is under the GNU Affero GPLv3 license | |
93 | - ``` | |
94 | - | |
95 | -# Controls what gets rate limited. When this is set to 'all', all content is | |
96 | -# rate limited. If this is 'nongemini', then anything that is **NOT** of type | |
97 | -# text/gemini is rate limited. | |
98 | -rate-limit-type: nongemini | |
99 | - | |
100 | -# Which network addresses to listen on. There must be at least one. | |
101 | -listen: | |
102 | - - localhost | |
103 | - #- 192.168.1.1 |
@@ -1,14 +0,0 @@ | ||
1 | -version: 2.0 | |
2 | -shards: | |
3 | - idle-gc: | |
4 | - git: https://github.com/compumike/idle-gc.git | |
5 | - version: 1.0.1 | |
6 | - | |
7 | - libremiliacr: | |
8 | - fossil: https://chiselapp.com/user/MistressRemilia/repository/libremiliacr | |
9 | - version: 0.11.2+fossil.commit.319b5887393250591f7091fdc25d158d4c479fee3c34f0a91d98d669e687c29b | |
10 | - | |
11 | - remigemini: | |
12 | - fossil: https://chiselapp.com/user/MistressRemilia/repository/remigemini | |
13 | - version: 0.2.1+fossil.commit.55f3ab9502a299e6d6291b2689eb7744492fee668bb8e62ca2ba11958459ffbd | |
14 | - |
@@ -1,19 +0,0 @@ | ||
1 | -name: aya | |
2 | -version: 0.3.0 | |
3 | -crystal: 1.5.0 | |
4 | -license: AGPLv3 | |
5 | - | |
6 | -authors: | |
7 | - - Remilia Scarlet <remilia@posteo.jp> | |
8 | - | |
9 | -targets: | |
10 | - aya: | |
11 | - main: src/main.cr | |
12 | - | |
13 | -dependencies: | |
14 | - remigemini: | |
15 | - fossil: https://chiselapp.com/user/MistressRemilia/repository/remigemini | |
16 | - commit: 55f3ab9502a299e6d6291b2689eb7744492fee668bb8e62ca2ba11958459ffbd | |
17 | - | |
18 | - idle-gc: | |
19 | - github: compumike/idle-gc |
@@ -1,195 +0,0 @@ | ||
1 | -#### Aya - A Gemini server | |
2 | -#### Copyright (C) 2021-2022 Remilia Scarlet <remilia@posteo.jp> | |
3 | -#### | |
4 | -#### This program is free software: you can redistribute it and/or modify | |
5 | -#### it under the terms of the GNU Affero General Public License as | |
6 | -#### published by the Free Software Foundation, either version 3 of the | |
7 | -#### License, or (at your option) any later version. | |
8 | -#### | |
9 | -#### This program is distributed in the hope that it will be useful, | |
10 | -#### but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | -#### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | -#### GNU Affero General Public License for more details. | |
13 | -#### | |
14 | -#### You should have received a copy of the GNU Affero General Public License | |
15 | -#### along with this program. If not, see <https://www.gnu.org/licenses/>. | |
16 | -require "yaml" | |
17 | - | |
18 | -module Aya | |
19 | - struct Config | |
20 | - include YAML::Serializable | |
21 | - include YAML::Serializable::Strict | |
22 | - | |
23 | - # Dictates how symlinks are handled. | |
24 | - enum FollowType | |
25 | - None | |
26 | - All | |
27 | - end | |
28 | - | |
29 | - # Specifies the rate limiting behavior. | |
30 | - enum RateLimitBehavior | |
31 | - All | |
32 | - NonGemini | |
33 | - end | |
34 | - | |
35 | - # Where to look for files to serve. | |
36 | - @[YAML::Field(key: "server-root")] | |
37 | - getter serverRoot : String | |
38 | - | |
39 | - # The port number to use for connections. | |
40 | - @[YAML::Field(key: "listen-port")] | |
41 | - getter listenPort : UInt16 = 1965u16 | |
42 | - | |
43 | - # Specifies how symlinks should be handled. | |
44 | - @[YAML::Field(key: "follow-symlinks")] | |
45 | - getter followSymlinks : FollowType = FollowType::None | |
46 | - | |
47 | - # If this is non-`nil`, this tells Aya to append a footer onto the end of | |
48 | - # every Gemtext page served. | |
49 | - getter footer : String? = nil | |
50 | - | |
51 | - # Where to find a mime.types file for MIME media type information. If this | |
52 | - # is `nil` (the default), then the default behavior of the `MIME` is used, | |
53 | - # with handlers for text/gemini added. | |
54 | - @[YAML::Field(key: "mime-file", emit_null: true)] | |
55 | - getter mimeFile : String? = nil | |
56 | - | |
57 | - # The location of the TLS certificate key. | |
58 | - @[YAML::Field(key: "tls-key")] | |
59 | - getter tlsKey : String | |
60 | - | |
61 | - # The location of the certificate chain | |
62 | - @[YAML::Field(key: "cert-chain")] | |
63 | - getter certChain : String | |
64 | - | |
65 | - # When non-nil, change to this UID after startup. If this is not specified, | |
66 | - # it uses the UID of whoever started the program. | |
67 | - getter uid : Int32? | |
68 | - | |
69 | - # When non-nil, change to this GID after startup. If this is not specified, | |
70 | - # it uses the GID of whoever started the program. | |
71 | - getter gid : Int32? | |
72 | - | |
73 | - # Dictates how files of unknown MIME media types are served. If this is | |
74 | - # `true`, files of unknown types are served as application/octet-stream. | |
75 | - # Otherwise they are not served, error type 40 is sent, and an error is | |
76 | - # printed on the console. | |
77 | - @[YAML::Field(key: "unknown-as-octet-stream")] | |
78 | - getter unknownAsOctetStream : Bool = false | |
79 | - | |
80 | - # When this is non-`nil`, all messages that are logged to standard | |
81 | - # output/standard error will be logged to this file as well. | |
82 | - @[YAML::Field(key: "log-file", emit_null: true)] | |
83 | - getter logFile : String? = nil | |
84 | - | |
85 | - # When this is a non-`nil`, all connections are logged here. This cannot be | |
86 | - # the same as `#logFile`. | |
87 | - @[YAML::Field(key: "conn-log-file", emit_null: true)] | |
88 | - getter connLogFile : String? = nil | |
89 | - | |
90 | - # When greater than zero, limit transfers to this number of kilobytes per | |
91 | - # second. | |
92 | - @[YAML::Field(key: "rate-limit")] | |
93 | - getter rateLimit : UInt64 = 0u64 | |
94 | - | |
95 | - # Controls what gets rate limited. When this is set to | |
96 | - # `RateLimitBehavior::All`, all content is rate limited. If this is | |
97 | - # `RateLimitBehavior::NonGemini`, then anything that is _not_ of type | |
98 | - # text/gemini is rate limited. | |
99 | - @[YAML::Field(key: "rate-limit-type")] | |
100 | - getter rateLimitType : RateLimitBehavior = RateLimitBehavior::NonGemini | |
101 | - | |
102 | - # Which network addresses to listen on. There must be at least one. | |
103 | - getter listen : Array(String) = ["127.0.0.1"] | |
104 | - | |
105 | - # Files with these extensions will be treated as CGI programs to execute. | |
106 | - # Anything sent to standard output by these programs will be served as a | |
107 | - # response body. Output should include the response header and any | |
108 | - # applicable body. This should never be an empty list. | |
109 | - # | |
110 | - # Be sure to include the dot (.) in the extension name. | |
111 | - @[YAML::Field(key: "cgi-extensions")] | |
112 | - getter cgiExtensions : Array(String) = [".cgi"] | |
113 | - | |
114 | - # What to use for the PATH environment variable for CGI scripts. This is | |
115 | - # passed verbatim to the PATH environment variable when invoking a CGI | |
116 | - # script. | |
117 | - @[YAML::Field(key: "cgi-path")] | |
118 | - getter cgiPath : String = "" | |
119 | - | |
120 | - # Creates a new (but useless) `Config` instance. | |
121 | - def initialize | |
122 | - @serverRoot = "" | |
123 | - @tlsKey = "" | |
124 | - @certChain = "" | |
125 | - end | |
126 | - | |
127 | - # Creates a new `Config` by loading one from `path`. If `path` doesn't | |
128 | - # exist, or the file cannot be loaded, this will call | |
129 | - # `RemiLib::Logger#fatal` with an appropriate error message. | |
130 | - def self.fromFile(path : String|Path) | |
131 | - begin | |
132 | - if File.exists?(path) | |
133 | - @@config = Config.from_yaml(File.open(path)) | |
134 | - else | |
135 | - RemiLib.log.fatal("Cannot find file: #{path}") | |
136 | - end | |
137 | - rescue err : YAML::Error | |
138 | - RemiLib.log.fatal("#{err}") | |
139 | - end | |
140 | - end | |
141 | - | |
142 | - # Performs various checks to see if this is a valid config file. If it | |
143 | - # isn't, this will call `RemiLib::Logger#fatal` with the appropriate | |
144 | - # message. | |
145 | - def validate : Nil | |
146 | - if @serverRoot.empty? | |
147 | - RemiLib.log.fatal("Server root path is empty") | |
148 | - elsif !Dir.exists?(@serverRoot) | |
149 | - RemiLib.log.fatal("Server root does not exist: #{Aya.config.serverRoot}") | |
150 | - end | |
151 | - | |
152 | - if @tlsKey.empty? | |
153 | - RemiLib.log.fatal("TLS certificate key path is empty") | |
154 | - elsif !File.exists?(@tlsKey) | |
155 | - RemiLib.log.fatal("TLS certificate key does not exist: #{Aya.config.tlsKey}") | |
156 | - end | |
157 | - | |
158 | - if @certChain.empty? | |
159 | - RemiLib.log.fatal("TLS certificate key path is empty") | |
160 | - elsif !File.exists?(@certChain) | |
161 | - RemiLib.log.fatal("TLS certificate chain does not exist: #{Aya.config.certChain}") | |
162 | - end | |
163 | - | |
164 | - if (mime = @mimeFile) && !File.exists?(mime) | |
165 | - RemiLib.log.fatal("MIME types file does not exist: #{mime}") | |
166 | - end | |
167 | - | |
168 | - if @listen.empty? | |
169 | - RemiLib.log.fatal("No interfaces to listen on") | |
170 | - end | |
171 | - | |
172 | - if @cgiExtensions.empty? | |
173 | - RemiLib.log.fatal("No CGI extensions defined") | |
174 | - end | |
175 | - | |
176 | - if (logpath = @logFile) | |
177 | - if (connpath = @connLogFile) | |
178 | - logpath = Path[logpath].normalize | |
179 | - connpath = Path[connpath].normalize | |
180 | - if connpath == logpath | |
181 | - RemiLib.log.fatal("log-file and conn-log-file cannot point to the same file") | |
182 | - end | |
183 | - end | |
184 | - end | |
185 | - end | |
186 | - | |
187 | - def self.dump(dest : String|Path) : Nil | |
188 | - File.open(dest, "w") { |file| Config.dump(file) } | |
189 | - end | |
190 | - | |
191 | - def self.dump(dest : IO) : Nil | |
192 | - dest << Config.new.to_yaml | |
193 | - end | |
194 | - end | |
195 | -end |
@@ -1,267 +0,0 @@ | ||
1 | -#### Aya - A Gemini server | |
2 | -#### Copyright (C) 2021-2022 Remilia Scarlet <remilia@posteo.jp> | |
3 | -#### | |
4 | -#### This program is free software: you can redistribute it and/or modify | |
5 | -#### it under the terms of the GNU Affero General Public License as | |
6 | -#### published by the Free Software Foundation, either version 3 of the | |
7 | -#### License, or (at your option) any later version. | |
8 | -#### | |
9 | -#### This program is distributed in the hope that it will be useful, | |
10 | -#### but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | -#### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | -#### GNU Affero General Public License for more details. | |
13 | -#### | |
14 | -#### You should have received a copy of the GNU Affero General Public License | |
15 | -#### along with this program. If not, see <https://www.gnu.org/licenses/>. | |
16 | -require "mime" | |
17 | -require "yaml" | |
18 | -require "libremiliacr" | |
19 | -require "idle-gc" | |
20 | -require "./utils" | |
21 | -require "./config" | |
22 | -require "./server" | |
23 | - | |
24 | -module Aya | |
25 | - # The current version of the program. | |
26 | - VERSION = "0.3.0" | |
27 | - | |
28 | - # The default system-wide configuration file. | |
29 | - DEFAULT_CONFIG_FILE = "/etc/aya/aya-config.yaml" | |
30 | - | |
31 | - # The MIME type for Gemtext. | |
32 | - GEMINI_MIME_TYPE = "text/gemini; charset=utf-8" | |
33 | - | |
34 | - # These are the command line arguments. | |
35 | - @@args : RemiLib::Args::ArgParser = RemiLib::Args::ArgParser.new("Aya", VERSION) | |
36 | - class_getter args | |
37 | - | |
38 | - # The loaded configuration file. | |
39 | - @@config : Config? = nil | |
40 | - class_getter! config | |
41 | - | |
42 | - # When non-nil, this is a separate logger used to log connections. | |
43 | - @@connLogger : RemiLib::ConcurrentLogger? = nil | |
44 | - class_getter connLogger | |
45 | - | |
46 | - # The OpenSSL context to use for connections. | |
47 | - @@sslCtx : OpenSSL::SSL::Context::Server? = nil | |
48 | - class_getter! sslCtx | |
49 | - | |
50 | - # Initializes the command line arguments, then parses them. | |
51 | - private def self.initCmdLine | |
52 | - @@args.addString("config", 'c', help: "The configuration file to load") | |
53 | - @@args.addFlag("init-only", 'I', help: "Initialize, but do not start, Aya.") | |
54 | - @@args.addString("dump-config", help: "Dumps a fresh, default config to the given destination, then exits. The destination can be '-' to dump to standard output.") | |
55 | - @@args.addString("pid", 'P', help: "Write the PID of the progress to the destination. It will be deleted when the program exists.") | |
56 | - @@args.addFlag("verbose", 'v', group: "Logging", help: "Enable verbose messages") | |
57 | - @@args.addFlag("debug", 'g', group: "Logging", help: "Enable debug messages") | |
58 | - | |
59 | - begin | |
60 | - @@args.parse | |
61 | - rescue err : RemiLib::Args::ArgumentError | |
62 | - RemiLib.log.fatal("#{err}") | |
63 | - end | |
64 | - end | |
65 | - | |
66 | - # Initializes basic logging settings for the main `RemiLib.log` instance. | |
67 | - # This does NOT initialize any log files or the connection logging. | |
68 | - private def self.initLogging | |
69 | - if @@args["verbose"].called? | |
70 | - RemiLib.log.verbosityLevel = 255u8 | |
71 | - end | |
72 | - | |
73 | - if @@args["debug"].called? | |
74 | - RemiLib.log.debugLevel = 255u8 | |
75 | - RemiLib.log.verbosityLevel = 255u8 | |
76 | - end | |
77 | - | |
78 | - RemiLib.log.timestamp = "%c" | |
79 | - RemiLib.log.defaultHeader = "Aya" | |
80 | - RemiLib.log.forceFlush = true | |
81 | - end | |
82 | - | |
83 | - private def self.initLogFiles | |
84 | - if (logfile = Aya.config.logFile) | |
85 | - begin | |
86 | - RemiLib.log.vlog("Init log file: #{logfile}") | |
87 | - RemiLib.log.otherStreams << File.open(logfile, "a") | |
88 | - rescue err : File::Error | |
89 | - RemiLib.log.fatal("Cannot open log file: #{err}") | |
90 | - end | |
91 | - end | |
92 | - | |
93 | - if (connFile = Aya.config.connLogFile) | |
94 | - begin | |
95 | - RemiLib.log.log("Logging connections to #{connFile}") | |
96 | - file = File.open(connFile, "a") | |
97 | - @@connLogger = RemiLib::ConcurrentLogger.new | |
98 | - @@connLogger.not_nil!.forceFlush = true | |
99 | - @@connLogger.not_nil!.defaultStream = file | |
100 | - @@connLogger.not_nil!.debugStream = file | |
101 | - @@connLogger.not_nil!.warnStream = file | |
102 | - @@connLogger.not_nil!.errorStream = file | |
103 | - @@connLogger.not_nil!.timestamp = "%c" | |
104 | - @@connLogger.not_nil!.defaultHeader = "Connection" | |
105 | - @@connLogger.not_nil!.start | |
106 | - rescue err : File::Error | |
107 | - RemiLib.log.fatal("Cannot open connection log file: #{err}") | |
108 | - end | |
109 | - else | |
110 | - RemiLib.log.log("Not logging connections") | |
111 | - end | |
112 | - end | |
113 | - | |
114 | - | |
115 | - # Loads the configuration file. If `--config`/`-c` is used, then the | |
116 | - # specified configuration file is loaded. Otherwise, an attempt is made to | |
117 | - # load the config located at `DEFAULT_CONFIG_FILE`. This will quit the | |
118 | - # program if no configuration file could be found. | |
119 | - private def self.initConfig | |
120 | - RemiLib.log.vlog("Init configuration file") | |
121 | - | |
122 | - if @@args["config"].called? | |
123 | - @@config = Config.fromFile(@@args["config"].str) | |
124 | - elsif File.exists?(DEFAULT_CONFIG_FILE) | |
125 | - @@config = Config.fromFile(DEFAULT_CONFIG_FILE) | |
126 | - else | |
127 | - RemiLib.log.fatal("No configuration file found#{!@@args["config"].called? ? " and none specified" : ""}") | |
128 | - end | |
129 | - | |
130 | - # Make sure the config is all good. | |
131 | - Aya.config.validate | |
132 | - end | |
133 | - | |
134 | - # Initializes the MIME types. | |
135 | - private def self.initMime | |
136 | - RemiLib.log.vlog("Init MIME database") | |
137 | - if (mimeFile = Aya.config.mimeFile) | |
138 | - RemiLib.log.vlog("Loading MIME type database: #{Aya.config.mimeFile}") | |
139 | - File.open(mimeFile) do |file| | |
140 | - MIME.load_mime_database(file) | |
141 | - end | |
142 | - end | |
143 | - end | |
144 | - | |
145 | - # Handle SIGINT signals. | |
146 | - Signal::INT.trap do | |
147 | - RemiLib.log.log("Ctrl-C detected, shutting down...") | |
148 | - RemiLib.log.otherStreams.each &.flush | |
149 | - RemiLib.log.otherStreams.each &.close | |
150 | - exit | |
151 | - end | |
152 | - | |
153 | - # Handle SIGTERM signals. | |
154 | - Signal::TERM.trap do | |
155 | - RemiLib.log.log("TERM signal detected, shutting down...") | |
156 | - RemiLib.log.otherStreams.each &.flush | |
157 | - RemiLib.log.otherStreams.each &.close | |
158 | - exit | |
159 | - end | |
160 | - | |
161 | - # Possibly excessive? | |
162 | - at_exit do | |
163 | - if @@args["pid"].called? && File.exists?(@@args["pid"].str) | |
164 | - File.delete(@@args["pid"].str) | |
165 | - end | |
166 | - | |
167 | - RemiLib.log.otherStreams.each &.flush | |
168 | - RemiLib.log.otherStreams.each &.close | |
169 | - end | |
170 | - | |
171 | - # Setup and parse command line arguments, then initialize the loggers | |
172 | - initCmdLine | |
173 | - initLogging | |
174 | - | |
175 | - @@args.withCalledStringArg("dump-config") do |arg| | |
176 | - begin | |
177 | - if arg.value == "-" | |
178 | - Config.dump(STDOUT) | |
179 | - STDOUT << '\n' | |
180 | - STDOUT.flush | |
181 | - else | |
182 | - Config.dump(arg.value) | |
183 | - puts "Dumped a new config to #{arg.value}" | |
184 | - end | |
185 | - exit 0 | |
186 | - rescue err : Exception | |
187 | - RemiLib.log.fatal("Could not dump config file: #{err}") | |
188 | - end | |
189 | - end | |
190 | - | |
191 | - # Initialize config file and MIME table | |
192 | - initConfig | |
193 | - initMime | |
194 | - | |
195 | - # Exit if --init-only was used | |
196 | - exit 0 if @@args["init-only"].called? | |
197 | - | |
198 | - # Create the SSL context. We do this before changing UID/GID because, if Aya | |
199 | - # is started as root but changes to a non-privileged user, then ideally the | |
200 | - # key/cert chain are owned by root and not the target user. | |
201 | - begin | |
202 | - RemiLib.log.log("Loading SSL key and certificate chain") | |
203 | - @@sslCtx = RemiGemini::Server.makeSSLContext(Aya.config.tlsKey, Aya.config.certChain) | |
204 | - rescue err : Exception | |
205 | - RemiLib.log.fatal("Could not create TLS context: #{err}") | |
206 | - end | |
207 | - | |
208 | - # Possibly create a PID file. | |
209 | - @@args.withCalledStringArg("pid") do |arg| | |
210 | - begin | |
211 | - File.open(arg.value, "w") do |file| | |
212 | - file << Process.pid | |
213 | - end | |
214 | - rescue err : Exception | |
215 | - RemiLib.log.fatal("Could not write PID to #{arg.value}: #{err}") | |
216 | - end | |
217 | - | |
218 | - # Change ownership | |
219 | - begin | |
220 | - File.chmod(arg.value, 0o0644) | |
221 | - uid = Aya.config.uid | |
222 | - gid = Aya.config.gid | |
223 | - | |
224 | - if uid | |
225 | - if gid | |
226 | - File.chown(arg.value, uid: uid, gid: gid) | |
227 | - else | |
228 | - File.chown(arg.value, uid: uid) | |
229 | - end | |
230 | - elsif gid | |
231 | - File.chown(arg.value, gid: gid) | |
232 | - end | |
233 | - rescue err : Exception | |
234 | - RemiLib.log.fatal("Could not write PID to #{arg.value}: #{err}") | |
235 | - end | |
236 | - end | |
237 | - | |
238 | - # Change UID/GID as-needed. The GID must be set first in case the new UID | |
239 | - # does not have permissions to change the GID. | |
240 | - if (gid = Aya.config.gid) | |
241 | - RemiLib.log.log("Changing GID to #{gid}") | |
242 | - unless (err = LibC.setregid(gid, gid)) == 0 | |
243 | - RemiLib.log.fatal("Could not change GID, error #{Errno.value}") | |
244 | - end | |
245 | - elsif LibC.getgid == 0 | |
246 | - RemiLib.log.warn("You are running as the root group!") | |
247 | - end | |
248 | - | |
249 | - if (uid = Aya.config.uid) | |
250 | - RemiLib.log.log("Changing UID to #{uid}") | |
251 | - unless (err = LibC.setreuid(uid, uid)) == 0 | |
252 | - RemiLib.log.fatal("Could not change UID, error #{Errno.value}") | |
253 | - end | |
254 | - elsif LibC.getuid == 0 | |
255 | - RemiLib.log.warn("You are running as root!") | |
256 | - end | |
257 | - | |
258 | - RemiLib.log.warn("Real UID is still root!") if LibC.geteuid() == 0 | |
259 | - RemiLib.log.warn("Real GID is still root!") if LibC.getegid() == 0 | |
260 | - | |
261 | - # Initialize log files | |
262 | - initLogFiles | |
263 | - | |
264 | - # Initialize IdleGC, then start the server | |
265 | - IdleGC.start | |
266 | - Server.new.run | |
267 | -end |
@@ -1,248 +0,0 @@ | ||
1 | -#### Aya - A Gemini server | |
2 | -#### Copyright (C) 2021-2022 Remilia Scarlet <remilia@posteo.jp> | |
3 | -#### | |
4 | -#### This program is free software: you can redistribute it and/or modify | |
5 | -#### it under the terms of the GNU Affero General Public License as | |
6 | -#### published by the Free Software Foundation, either version 3 of the | |
7 | -#### License, or (at your option) any later version. | |
8 | -#### | |
9 | -#### This program is distributed in the hope that it will be useful, | |
10 | -#### but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | -#### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | -#### GNU Affero General Public License for more details. | |
13 | -#### | |
14 | -#### You should have received a copy of the GNU Affero General Public License | |
15 | -#### along with this program. If not, see <https://www.gnu.org/licenses/>. | |
16 | -require "remigemini" | |
17 | - | |
18 | -module Aya | |
19 | - SHOW_DIRECTORY_FILE = ".showdir" | |
20 | - | |
21 | - class Server | |
22 | - @serv : RemiGemini::Server | |
23 | - | |
24 | - def initialize | |
25 | - RemiLib.log.log("Init server") | |
26 | - @serv = RemiGemini::Server.new(->handleConnection(RemiGemini::Server::Request)) | |
27 | - end | |
28 | - | |
29 | - def run | |
30 | - RemiLib.log.log("Starting server") | |
31 | - Aya.config.listen.each do |addr| | |
32 | - begin | |
33 | - fancyAddr = @serv.bind(addr, Aya.sslCtx, port: Aya.config.listenPort) | |
34 | - RemiLib.log.log("Listening on gemini://#{fancyAddr}") | |
35 | - rescue err : Exception | |
36 | - RemiLib.log.error("#{err}") | |
37 | - end | |
38 | - end | |
39 | - | |
40 | - @serv.listen | |
41 | - end | |
42 | - | |
43 | - private def transferFile(sock : IO, mtype : String, path : Path) | |
44 | - File.open(path) do |infile| | |
45 | - if Aya.config.rateLimit > 0 && (Aya.config.rateLimitType.all? || mtype != GEMINI_MIME_TYPE) | |
46 | - sock.rateLimitedCopy(Aya.config.rateLimit * 1024, infile) | |
47 | - else | |
48 | - IO.copy(infile, sock) | |
49 | - end | |
50 | - end | |
51 | - | |
52 | - if mtype == GEMINI_MIME_TYPE | |
53 | - Aya.config.footer.try { |str| sock << '\n' << str << '\n' } | |
54 | - end | |
55 | - end | |
56 | - | |
57 | - private def validURI?(uri : URI) : Bool | |
58 | - return false unless uri.scheme == "gemini" | |
59 | - return false unless uri.host | |
60 | - return false if uri.userinfo | |
61 | - true | |
62 | - end | |
63 | - | |
64 | - private def serveDirectory(sock, uri, path) | |
65 | - uriPath = Path[uri.path] | |
66 | - | |
67 | - gemtext = String.build do |str| | |
68 | - str << "# Listing of #{uri}\n\n" | |
69 | - | |
70 | - if inServerRoot?(path.parent) && File.exists?(Dir[path.parent].join(SHOW_DIRECTORY_FILE)) | |
71 | - str << "=> #{uriPath.parent} (up one directory)\n" | |
72 | - end | |
73 | - | |
74 | - Dir.each_child(path) do |child| | |
75 | - fullpath = path.join(child) | |
76 | - unless File.info(fullpath).symlink? || fullpath.basename == SHOW_DIRECTORY_FILE | |
77 | - str << "=> #{uriPath.join(child)} #{child}\n" | |
78 | - end | |
79 | - end | |
80 | - end | |
81 | - | |
82 | - sock << "20 #{GEMINI_MIME_TYPE}\r\n" | |
83 | - sock << gemtext | |
84 | - Aya.config.footer.try { |str| sock << '\n' << str << '\n' } | |
85 | - return | |
86 | - end | |
87 | - | |
88 | - private def inServerRoot?(path : Path) : Bool | |
89 | - begin | |
90 | - otherParts = path.parts | |
91 | - Path[Aya.config.serverRoot].parts.each_with_index do |part, idx| | |
92 | - return false unless otherParts[idx] == part | |
93 | - end | |
94 | - rescue Exception | |
95 | - return false | |
96 | - end | |
97 | - | |
98 | - true | |
99 | - end | |
100 | - | |
101 | - def handleConnection(req : RemiGemini::Server::Request) : Nil | |
102 | - uri = req.uri | |
103 | - sock = req.sock.as?(OpenSSL::SSL::Socket) | |
104 | - unless sock | |
105 | - RemiLib.log.error("RemiGemini library gave us a socket of type #{req.sock.class}") | |
106 | - req.sock << "40 Internal error\r\n" | |
107 | - return | |
108 | - end | |
109 | - | |
110 | - begin | |
111 | - # Convert the URI's path into a Path instance | |
112 | - path = Path[Aya.config.serverRoot].join(uri.path).normalize | |
113 | - | |
114 | - # Path must be inside the server root | |
115 | - unless inServerRoot?(path) | |
116 | - Aya.connLogger.try &.log("#{sock.local_address} :: 51 Not Found: #{uri.path}") | |
117 | - sock << "51 Not found: #{uri.path}\r\n" | |
118 | - return | |
119 | - end | |
120 | - | |
121 | - if Dir.exists?(path) | |
122 | - if File.exists?(path.join(SHOW_DIRECTORY_FILE)) | |
123 | - # Generate a dynamic directory listing | |
124 | - serveDirectory(sock, uri, path) | |
125 | - return | |
126 | - else | |
127 | - # Append index.gmi to the path | |
128 | - path = path.join("index.gmi") | |
129 | - end | |
130 | - elsif path.basename == SHOW_DIRECTORY_FILE | |
131 | - # Never serve .showdir files | |
132 | - Aya.connLogger.try &.log("#{sock.local_address} :: 51 Not Found: #{uri.path}") | |
133 | - sock << "51 Not found: #{uri.path}\r\n" | |
134 | - return | |
135 | - else | |
136 | - # Requested file must exist | |
137 | - unless File.exists?(path) | |
138 | - Aya.connLogger.try &.log("#{sock.local_address} :: 51 Not Found: #{uri.path}") | |
139 | - sock << "51 Not found: #{uri.path}\r\n" | |
140 | - return | |
141 | - end | |
142 | - end | |
143 | - | |
144 | - # Requested file must exist | |
145 | - unless File.exists?(path) | |
146 | - Aya.connLogger.try &.log("#{sock.local_address} :: 51 Not Found: #{uri.path}") | |
147 | - sock << "51 Not found: #{uri.path}\r\n" | |
148 | - return | |
149 | - end | |
150 | - | |
151 | - # Handle symlinks | |
152 | - if File.info(path).symlink? && Aya.config.followSymlinks.none? | |
153 | - Aya.connLogger.try &.log("#{sock.local_address} :: 51 Not Found: #{uri.path}") | |
154 | - sock << "51 Not found\r\n" | |
155 | - return | |
156 | - end | |
157 | - | |
158 | - path.each_parent do |parent| | |
159 | - if File.info(parent).symlink? && Aya.config.followSymlinks.none? | |
160 | - Aya.connLogger.try &.log("#{sock.local_address} :: 51 Not Found: #{uri.path}") | |
161 | - sock << "51 Not found\r\n" | |
162 | - return | |
163 | - end | |
164 | - end | |
165 | - | |
166 | - # CGI script? Handle that separately. | |
167 | - if Aya.config.cgiExtensions.includes?(path.extension) | |
168 | - handleCGI(sock, uri, path) | |
169 | - return | |
170 | - end | |
171 | - | |
172 | - # Serve the request | |
173 | - begin | |
174 | - mtype = MIME.from_filename?(path) | |
175 | - unless mtype | |
176 | - if Aya.config.unknownAsOctetStream | |
177 | - mtype = "application/octet-stream" | |
178 | - else | |
179 | - sock << "40 Internal error\r\n" | |
180 | - RemiLib.log.error("Cannot serve file, unknown MIME type: #{path}") | |
181 | - return | |
182 | - end | |
183 | - end | |
184 | - | |
185 | - Aya.connLogger.try &.log("#{sock.local_address} :: 20: #{uri.path}") | |
186 | - sock << "20 #{mtype.not_nil!}\r\n" | |
187 | - transferFile(sock, mtype, path) | |
188 | - IdleGC.background_collect | |
189 | - rescue err : File::NotFoundError | |
190 | - sock << "51 Not found: #{uri.path}\r\n" | |
191 | - return | |
192 | - end | |
193 | - rescue err : Exception | |
194 | - Aya.connLogger.try &.log("#{sock.local_address} :: 40 Internal error: #{uri.path}") | |
195 | - sock << "40 Internal error\r\n" | |
196 | - RemiLib.log.error("#{typeof(err)} while attempting to serve #{uri}") | |
197 | - RemiLib.log.error(err) | |
198 | - ensure | |
199 | - sock.close | |
200 | - end | |
201 | - end | |
202 | - | |
203 | - private def handleCGI(sock, uri, path) | |
204 | - # Setup the environment we'll use for the process. | |
205 | - env = {} of String => String | |
206 | - env["DOCUMENT_ROOT"] = Aya.config.serverRoot | |
207 | - env["GATEWAY_INTERFACE"] = "ACGI 0.1.0" # "Aya CGI" with symver | |
208 | - env["PATH_INFO"] = uri.path || "" | |
209 | - env["PATH_TRANSLATED"] = path.to_s | |
210 | - env["SCRIPT_FILENAME"] = path.basename.to_s | |
211 | - env["QUERY_STRING"] = uri.query || "" | |
212 | - env["REQUEST_FRAGMENT"] = uri.fragment || "" | |
213 | - env["SERVER_HOST"] = uri.host || "" | |
214 | - env["SERVER_PORT"] = uri.port.try &.to_s || Aya.config.listenPort.to_s | |
215 | - env["PATH"] = Aya.config.cgiPath | |
216 | - | |
217 | - begin | |
218 | - # Start the process and connect I/O | |
219 | - proc = Process.new(path.to_s, env: env, clear_env: true, | |
220 | - input: Process::Redirect::Pipe, output: Process::Redirect::Pipe, | |
221 | - error: Process::Redirect::Pipe) | |
222 | - # HACK This will easily eat ram. | |
223 | - result = proc.output.gets_to_end | |
224 | - error = proc.error.gets_to_end | |
225 | - | |
226 | - # Wait for the process to finish, then send a response. | |
227 | - status = proc.wait | |
228 | - if status.success? | |
229 | - sock << result | |
230 | - else | |
231 | - RemiLib.log.error("CGI script #{path} exited with status #{status.exit_code}") | |
232 | - Aya.connLogger.try &.log("#{sock.local_address} :: 40 Internal error: #{uri.path}") | |
233 | - sock << "40 Internal Error\r\n" | |
234 | - end | |
235 | - | |
236 | - # If we had output on stderr, log that now. | |
237 | - unless error.empty? | |
238 | - RemiLib.log.error("Error while executing #{path}: #{error}") | |
239 | - end | |
240 | - rescue err : IO::Error | |
241 | - # Process failed to start! D: | |
242 | - RemiLib.log.error("Error executing #{path}: #{err}") | |
243 | - Aya.connLogger.try &.log("#{sock.local_address} :: 40 Internal error: #{uri.path}") | |
244 | - sock << "40 Internal error\r\n" | |
245 | - end | |
246 | - end | |
247 | - end | |
248 | -end |
@@ -1,28 +0,0 @@ | ||
1 | -#### Aya - A Gemini server | |
2 | -#### Copyright (C) 2021-2022 Remilia Scarlet <remilia@posteo.jp> | |
3 | -#### | |
4 | -#### This program is free software: you can redistribute it and/or modify | |
5 | -#### it under the terms of the GNU Affero General Public License as | |
6 | -#### published by the Free Software Foundation, either version 3 of the | |
7 | -#### License, or (at your option) any later version. | |
8 | -#### | |
9 | -#### This program is distributed in the hope that it will be useful, | |
10 | -#### but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | -#### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | -#### GNU Affero General Public License for more details. | |
13 | -#### | |
14 | -#### You should have received a copy of the GNU Affero General Public License | |
15 | -#### along with this program. If not, see <https://www.gnu.org/licenses/>. | |
16 | - | |
17 | -lib LibC | |
18 | - # This was introduced in Crystal 1.4.0 | |
19 | - {% if compare_versions(Crystal::VERSION, "1.5.0") < 0 %} | |
20 | - fun getuid() : Int32 | |
21 | - {% end %} | |
22 | - | |
23 | - fun setregid(rgid : Int32, egid : Int32) : Int32 | |
24 | - fun setreuid(ruid : Int32, euid : Int32) : Int32 | |
25 | - fun getgid() : Int32 | |
26 | - fun geteuid() : Int32 | |
27 | - fun getegid() : Int32 | |
28 | -end |