docs(web): update the built-in technical manual
Bring the optional web manual into line with the new functionality and deployment process.
This commit is contained in:
1 parent
bd4cbc2471
commit
b36876ea45
1 file changed
+20
-14
+20
-14
@@ -36,6 +36,7 @@ def render_docs():
|
|||||||
<article class="docs-content">
|
<article class="docs-content">
|
||||||
<section id="start" class="docs-section">
|
<section id="start" class="docs-section">
|
||||||
<h2>Starting the server</h2>
|
<h2>Starting the server</h2>
|
||||||
|
<p>For a new installation, use <code>Start-OSE.cmd</code> on Windows or <code>sh start-ose.sh</code> on Linux/macOS. The scripts create a local virtual environment, install dependencies and run first-time setup. The repository's <code>GETTING_STARTED.md</code> has the full installation, update, backup and Linux service instructions. Direct Python starts remain supported.</p>
|
||||||
<p>The entry point is <code>server.py</code>. A normal start is:</p>
|
<p>The entry point is <code>server.py</code>. A normal start is:</p>
|
||||||
<pre><code>python3 -m pip install -r requirements.txt
|
<pre><code>python3 -m pip install -r requirements.txt
|
||||||
python3 server.py</code></pre>
|
python3 server.py</code></pre>
|
||||||
@@ -105,16 +106,20 @@ python3 server.py</code></pre>
|
|||||||
|
|
||||||
<section id="web" class="docs-section">
|
<section id="web" class="docs-section">
|
||||||
<h2>Web client</h2>
|
<h2>Web client</h2>
|
||||||
<p>The browser client is server-rendered HTML in <code>webapp.py</code>. It has no JavaScript framework and no browser session cookie. Each request asks the database for the account currently associated with the source IP.</p>
|
<p>The browser client is server-rendered HTML in <code>webapp.py</code>, <code>web_features.py</code> and <code>web_ui.py</code>. It has no JavaScript framework or account-session cookie: each request looks up the account associated with its source IP. A separate host-only CSRF cookie protects web forms; POST forms must carry its matching token. It does not change the account model.</p>
|
||||||
|
<h3>Browsing and creator tools</h3>
|
||||||
|
<p><code>/browse</code> shows 24 Flipnotes per page and preserves its search, sort and channel filters. <code>/search</code> finds Flipnotes or Creator's Rooms. <code>/channels</code> lists channels and links to their filtered pages. Creator's Rooms also use 24-item pagination; watch-page comments use 25 per page.</p>
|
||||||
|
<p>Owners and administrators can open <code>/watch/<public id>/manage</code> to change the title, description or channel, or remove the Flipnote. These are metadata/soft-delete actions, not PPM rewriting. Both GET and POST check OSE account/IP ownership. Original commenters can remove their own comments. A matching PPM FSID is not an independent ownership grant.</p>
|
||||||
|
<p>The administrator tabs are <strong>Flipnotes</strong>, <strong>Comments</strong>, <strong>Channels</strong>, <strong>Server</strong> and <strong>IP bans</strong>. Content lists are searchable and paginated, with hide/restore controls and optional reasons. Hidden content is still visible to website administrators; normal visitors and DSi routes treat it as absent. Removing a channel moves its Flipnotes into another existing channel. General remains the fallback channel. Server settings cover branding, a logo upload, registration, guest posting and the PPM size limit.</p>
|
||||||
<div class="docs-notice"><strong>Login notice.</strong> The web client uses the same deliberately simple IP identity model as the rest of OSE. Production session/device management was left out so that live authentication design, keys and account-security machinery are not copied into a public release. Shared addresses, proxies and changing IPs therefore have consequences described in the Accounts section below.</div>
|
<div class="docs-notice"><strong>Login notice.</strong> The web client uses the same deliberately simple IP identity model as the rest of OSE. Production session/device management was left out so that live authentication design, keys and account-security machinery are not copied into a public release. Shared addresses, proxies and changing IPs therefore have consequences described in the Accounts section below.</div>
|
||||||
<table class="docs-table"><thead><tr><th>Route</th><th>Method</th><th>Behaviour</th></tr></thead><tbody>
|
<table class="docs-table"><thead><tr><th>Route</th><th>Method</th><th>Behaviour</th></tr></thead><tbody>
|
||||||
<tr><td><code>/</code></td><td>GET</td><td>Home page with the most recent Flipnotes.</td></tr>
|
<tr><td><code>/</code></td><td>GET</td><td>Home page with the most recent Flipnotes.</td></tr>
|
||||||
<tr><td><code>/browse</code></td><td>GET</td><td>Browse up to 100 Flipnotes. <code>?sort=new</code>, <code>?sort=popular</code> and <code>?sort=top</code> map to posted time, views/stars and stars/views orderings.</td></tr>
|
<tr><td><code>/browse</code></td><td>GET</td><td>Paginated, searchable Flipnotes with channel filters and newest, popular or most-stars ordering.</td></tr>
|
||||||
<tr><td><code>/about</code></td><td>GET</td><td>Open-source credits and acknowledgements only.</td></tr>
|
<tr><td><code>/about</code></td><td>GET</td><td>Open-source credits and acknowledgements only.</td></tr>
|
||||||
<tr><td><code>/docs</code></td><td>GET</td><td>This manual, only when documentation is enabled at server start.</td></tr>
|
<tr><td><code>/docs</code></td><td>GET</td><td>This manual, only when documentation is enabled at server start.</td></tr>
|
||||||
<tr><td><code>/watch/<public id></code></td><td>GET</td><td>Flipnote detail page. It increments the view count, loads comments and shows other notes from the same Creator's Room.</td></tr>
|
<tr><td><code>/watch/<public id></code></td><td>GET</td><td>Flipnote detail page. It increments the view count, loads comments and shows other notes from the same Creator's Room.</td></tr>
|
||||||
<tr><td><code>/watch/<public id>/comment</code></td><td>POST</td><td>Adds a text comment using the current account or guest-IP Creator's Room.</td></tr>
|
<tr><td><code>/watch/<public id>/comment</code></td><td>POST</td><td>Adds a text comment using the current account or guest-IP Creator's Room.</td></tr>
|
||||||
<tr><td><code>/thumb/<public id>.png</code></td><td>GET</td><td>Decodes the first PPM frame and returns a cached PNG thumbnail.</td></tr>
|
<tr><td><code>/thumb/<public id>.png</code></td><td>GET</td><td>Saved thumbnail frame with hidden-layer flags respected; <code>?first=1</code> requests the player fallback's first frame.</td></tr>
|
||||||
<tr><td><code>/comment-thumb/<id>.png</code></td><td>GET</td><td>Returns a first-frame PNG preview for a mini-Flipnote comment.</td></tr>
|
<tr><td><code>/comment-thumb/<id>.png</code></td><td>GET</td><td>Returns a first-frame PNG preview for a mini-Flipnote comment.</td></tr>
|
||||||
<tr><td><code>/media/<public id>.ppm</code></td><td>GET</td><td>Returns the original PPM inline for browser playback. It does not increment the download counter.</td></tr>
|
<tr><td><code>/media/<public id>.ppm</code></td><td>GET</td><td>Returns the original PPM inline for browser playback. It does not increment the download counter.</td></tr>
|
||||||
<tr><td><code>/flipnote/<public id>.ppm</code></td><td>GET</td><td>Increments downloads and returns the original PPM as an attachment.</td></tr>
|
<tr><td><code>/flipnote/<public id>.ppm</code></td><td>GET</td><td>Increments downloads and returns the original PPM as an attachment.</td></tr>
|
||||||
@@ -123,7 +128,7 @@ python3 server.py</code></pre>
|
|||||||
<tr><td><code>/register</code></td><td>GET/POST</td><td>Creates an account and immediately associates the source IP with it.</td></tr>
|
<tr><td><code>/register</code></td><td>GET/POST</td><td>Creates an account and immediately associates the source IP with it.</td></tr>
|
||||||
<tr><td><code>/logout</code></td><td>GET</td><td>Deletes the current source IP from <code>ip_logins</code>.</td></tr>
|
<tr><td><code>/logout</code></td><td>GET</td><td>Deletes the current source IP from <code>ip_logins</code>.</td></tr>
|
||||||
<tr><td><code>/account</code></td><td>GET</td><td>Shows the signed-in username, current IP and Creator's Room link when one exists.</td></tr>
|
<tr><td><code>/account</code></td><td>GET</td><td>Shows the signed-in username, current IP and Creator's Room link when one exists.</td></tr>
|
||||||
<tr><td><code>/admin</code></td><td>GET</td><td>Minimal administrator view for IP bans and Flipnote deletion.</td></tr>
|
<tr><td><code>/admin</code></td><td>GET</td><td>Administrator tools for Flipnotes, comments, channels, server settings and IP bans.</td></tr>
|
||||||
<tr><td><code>/admin/ban</code></td><td>POST</td><td>Adds or updates an IP ban and clears that IP's login row.</td></tr>
|
<tr><td><code>/admin/ban</code></td><td>POST</td><td>Adds or updates an IP ban and clears that IP's login row.</td></tr>
|
||||||
<tr><td><code>/admin/unban</code></td><td>POST</td><td>Removes an IP ban.</td></tr>
|
<tr><td><code>/admin/unban</code></td><td>POST</td><td>Removes an IP ban.</td></tr>
|
||||||
<tr><td><code>/admin/delete</code></td><td>POST</td><td>Soft-deletes a Flipnote record by setting <code>deleted=1</code>.</td></tr>
|
<tr><td><code>/admin/delete</code></td><td>POST</td><td>Soft-deletes a Flipnote record by setting <code>deleted=1</code>.</td></tr>
|
||||||
@@ -135,10 +140,10 @@ python3 server.py</code></pre>
|
|||||||
<h2>Flipnote view page</h2>
|
<h2>Flipnote view page</h2>
|
||||||
<p>The watch page has browser playback as well as the server-generated first-frame fallback. <code>webapp.py</code> loads the pinned <code>flipnote.js</code> 6.3.1 browser build from jsDelivr, then loads the local <code>web/static/flipnote-player.js</code> controller. The controller creates a <code>flipnote.Player</code> at 320×240, asks it to load <code>/media/<public id>.ppm</code>, and lets flipnote.js decode the original PPM animation and audio in the browser. OSE does not pre-render a video, GIF or separate audio file.</p>
|
<p>The watch page has browser playback as well as the server-generated first-frame fallback. <code>webapp.py</code> loads the pinned <code>flipnote.js</code> 6.3.1 browser build from jsDelivr, then loads the local <code>web/static/flipnote-player.js</code> controller. The controller creates a <code>flipnote.Player</code> at 320×240, asks it to load <code>/media/<public id>.ppm</code>, and lets flipnote.js decode the original PPM animation and audio in the browser. OSE does not pre-render a video, GIF or separate audio file.</p>
|
||||||
<p>The player starts paused. Once flipnote.js reports that the note is ready, OSE hides the first-frame image and enables the large play button and the control row. The controls provide play/pause, a seek range, elapsed/total time, sound mute/unmute and loop on/off. Seeking uses flipnote.js's <code>startSeek()</code>, <code>seek()</code> and <code>endSeek()</code> calls so playback can resume cleanly after dragging. Clicking the rendered Flipnote toggles playback after the player has been started once.</p>
|
<p>The player starts paused. Once flipnote.js reports that the note is ready, OSE hides the first-frame image and enables the large play button and the control row. The controls provide play/pause, a seek range, elapsed/total time, sound mute/unmute and loop on/off. Seeking uses flipnote.js's <code>startSeek()</code>, <code>seek()</code> and <code>endSeek()</code> calls so playback can resume cleanly after dragging. Clicking the rendered Flipnote toggles playback after the player has been started once.</p>
|
||||||
<p><code>/media/<public id>.ppm</code> is deliberately separate from <code>/flipnote/<public id>.ppm</code>. The media route returns the same on-disk PPM with <code>Content-Disposition: inline</code> and a one-hour public cache header, but it does not call <code>Database.AddDownload()</code>. The download route remains the explicit <strong>Download PPM</strong> action, increments the download counter and returns the file as an attachment. Opening or replaying a watch page therefore does not count as a file download.</p>
|
<p><code>/media/<public id>.ppm</code> returns the original PPM inline without increasing downloads. <code>/flipnote/<public id>.ppm</code> is the explicit attachment download and increments that counter. Media and preview responses use <code>private, no-store</code>, so a viewed file cannot remain publicly cacheable after being hidden. Opening or replaying a watch page does not count as a file download.</p>
|
||||||
<p>The <code><img></code> first-frame preview remains in the page before JavaScript runs. If the flipnote.js global is missing, the browser cannot construct its canvas/WebAudio player, the PPM cannot be parsed, or playback reports an error, <code>flipnote-player.js</code> leaves that preview visible, disables the player controls and shows a short playback-unavailable message. The rest of the watch page still works normally. This also gives the page a useful non-JavaScript fallback.</p>
|
<p>The <code><img></code> first-frame preview remains in the page before JavaScript runs. If the flipnote.js global is missing, the browser cannot construct its canvas/WebAudio player, the PPM cannot be parsed, or playback reports an error, <code>flipnote-player.js</code> leaves that preview visible, disables the player controls and shows a short playback-unavailable message. The rest of the watch page still works normally. This also gives the page a useful non-JavaScript fallback.</p>
|
||||||
<div class="docs-notice"><strong>Browser dependency/privacy notice.</strong> The playback library is loaded from the jsDelivr CDN rather than copied into OSE. This keeps a large third-party build out of the repository, but it means a browser visiting a watch page makes a request to jsDelivr for <code>flipnote.min.js</code>. The PPM URL itself is same-origin and is not submitted to jsDelivr by OSE. An operator who does not want that third-party browser request should self-host the pinned flipnote.js build and change the script URL in <code>webapp.py</code>.</div>
|
<div class="docs-notice"><strong>Browser dependency/privacy notice.</strong> The playback library is loaded from the jsDelivr CDN rather than copied into OSE. This keeps a large third-party build out of the repository, but it means a browser visiting a watch page makes a request to jsDelivr for <code>flipnote.min.js</code>. The PPM URL itself is same-origin and is not submitted to jsDelivr by OSE. An operator who does not want that third-party browser request should self-host the pinned flipnote.js build and change the script URL in <code>webapp.py</code>.</div>
|
||||||
<p>Opening the page calls <code>Database.AddView()</code> before the Flipnote row is reloaded, so the displayed view count includes the current request. The page then loads up to 100 comments, the channel record, the Creator's Room record and a short list of other non-deleted Flipnotes from the same room.</p>
|
<p>Opening the page calls <code>Database.AddView()</code> before reloading the Flipnote row, so its displayed count includes the current request. It then loads a 25-comment page, the channel, the Creator's Room and a short list of other visible, non-deleted Flipnotes from that room.</p>
|
||||||
<p>The information panel displays stars, views, downloads and comment count, then the post time, channel, creator FSID, PPM filename and public identifier. These values come directly from the OSE SQLite row; there is no secondary profile, device or ownership lookup.</p>
|
<p>The information panel displays stars, views, downloads and comment count, then the post time, channel, creator FSID, PPM filename and public identifier. These values come directly from the OSE SQLite row; there is no secondary profile, device or ownership lookup.</p>
|
||||||
<div class="docs-notice"><strong>Metadata notice.</strong> Creator metadata shown here is repository data, not a cryptographically verified identity. OSE deliberately avoids the production ownership/device verification chain so those security mechanisms are not exposed in the public codebase. Treat FSIDs, embedded creator names and room ownership as local OSE identifiers.</div>
|
<div class="docs-notice"><strong>Metadata notice.</strong> Creator metadata shown here is repository data, not a cryptographically verified identity. OSE deliberately avoids the production ownership/device verification chain so those security mechanisms are not exposed in the public codebase. Treat FSIDs, embedded creator names and room ownership as local OSE identifiers.</div>
|
||||||
<p>Text comments are HTML-escaped. Mini-Flipnote comments are shown as first-frame thumbnails through <code>/comment-thumb/<id>.png</code>; the stored PPM is still the authoritative comment file used by the DSi endpoints.</p>
|
<p>Text comments are HTML-escaped. Mini-Flipnote comments are shown as first-frame thumbnails through <code>/comment-thumb/<id>.png</code>; the stored PPM is still the authoritative comment file used by the DSi endpoints.</p>
|
||||||
@@ -209,7 +214,7 @@ python3 server.py</code></pre>
|
|||||||
<p>There are no cookies or browser session identifiers in this flow. The DSi and browser clients see the same account when they reach the server from the same source IP. If traffic is behind a shared NAT or reverse proxy, the address visible to Twisted is the identity key used by OSE.</p>
|
<p>There are no cookies or browser session identifiers in this flow. The DSi and browser clients see the same account when they reach the server from the same source IP. If traffic is behind a shared NAT or reverse proxy, the address visible to Twisted is the identity key used by OSE.</p>
|
||||||
<div class="docs-notice"><strong>IP login notice.</strong> An IP address is only a convenient OSE ownership key. Addresses can be shared, reassigned, hidden behind NAT or represented by a reverse proxy. OSE uses this simpler local mapping so the public release does not contain RexiMemo's production session/device security implementation, reducing the risk of exposing live-service authentication behaviour. It is a release-safety compromise, not a secure substitute for a proper session design.</div>
|
<div class="docs-notice"><strong>IP login notice.</strong> An IP address is only a convenient OSE ownership key. Addresses can be shared, reassigned, hidden behind NAT or represented by a reverse proxy. OSE uses this simpler local mapping so the public release does not contain RexiMemo's production session/device security implementation, reducing the risk of exposing live-service authentication behaviour. It is a release-safety compromise, not a secure substitute for a proper session design.</div>
|
||||||
<p>The DSi account page uses <code>username:password</code> entered through the Flipnote Studio keyboard. The keyboard value arrives in <code>X-Email-Addr</code>. Registration creates the account, writes the IP login, and forwards back to <code>sa/account.htm</code> using <code>X-DSi-Forwarder</code>.</p>
|
<p>The DSi account page uses <code>username:password</code> entered through the Flipnote Studio keyboard. The keyboard value arrives in <code>X-Email-Addr</code>. Registration creates the account, writes the IP login, and forwards back to <code>sa/account.htm</code> using <code>X-DSi-Forwarder</code>.</p>
|
||||||
<p>The seeded administrator is <code>reximemo</code> with password <code>alpine</code>. It is created only when no account named <code>reximemo</code> exists in the opened database.</p>
|
<p>Before first-run setup, the seed administrator is <code>reximemo</code> with password <code>alpine</code>. It is created only when there is no administrator and setup has not been marked complete. <code>python manage.py setup</code> selects your administrator and disables the public default login if another account is chosen, preserving existing Creator's Rooms and media.</p>
|
||||||
<div class="docs-notice"><strong>Default credential notice.</strong> The seed login exists so a fresh checkout can exercise the admin page immediately. It is public repository data, not a secret. Change or remove it before exposing an OSE instance beyond a controlled test network.</div>
|
<div class="docs-notice"><strong>Default credential notice.</strong> The seed login exists so a fresh checkout can exercise the admin page immediately. It is public repository data, not a secret. Change or remove it before exposing an OSE instance beyond a controlled test network.</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -235,7 +240,7 @@ python3 server.py</code></pre>
|
|||||||
</tbody></table>
|
</tbody></table>
|
||||||
<p><code>flipnotes</code> has a uniqueness constraint on <code>(creator_fsid, filename)</code>. Public IDs are generated from <code>secrets.token_urlsafe()</code>, stripped of <code>-</code>/<code>_</code>, truncated, and prefixed according to object type. They are routing identifiers rather than authentication tokens.</p>
|
<p><code>flipnotes</code> has a uniqueness constraint on <code>(creator_fsid, filename)</code>. Public IDs are generated from <code>secrets.token_urlsafe()</code>, stripped of <code>-</code>/<code>_</code>, truncated, and prefixed according to object type. They are routing identifiers rather than authentication tokens.</p>
|
||||||
<div class="docs-notice"><strong>Database/privacy notice.</strong> OSE stores usernames, password digests, source IP login mappings, guest owner IPs and IP bans directly in SQLite. This is deliberately straightforward so the public release has no hidden account/session service or production datastore dependency. If you run a public instance, decide what IP retention, access control, backups and database-file permissions are appropriate for your environment.</div>
|
<div class="docs-notice"><strong>Database/privacy notice.</strong> OSE stores usernames, password digests, source IP login mappings, guest owner IPs and IP bans directly in SQLite. This is deliberately straightforward so the public release has no hidden account/session service or production datastore dependency. If you run a public instance, decide what IP retention, access control, backups and database-file permissions are appropriate for your environment.</div>
|
||||||
<p>Flipnote deletion is a soft delete. Listing and lookup queries require <code>deleted=0</code>; the PPM file is not erased by <code>delete_flipnote()</code>. Comments also carry a <code>deleted</code> column, although the OSE web admin does not expose comment moderation controls.</p>
|
<p>Flipnote deletion is a soft delete. Listing and lookup queries require <code>deleted=0</code>; the PPM file is not erased by <code>delete_flipnote()</code>. Flipnotes and comments also have a separate <code>hidden</code> flag and moderation reason. Public lists, counts, search, thumbnails and media exclude hidden content. Administrator queries explicitly request it, so an item can be restored without deleting or re-uploading it.</p>
|
||||||
<p>Sorting rules are defined in <code>list_flipnotes()</code>. Newest uses <code>posted_at DESC, id DESC</code>; Popular uses views, then stars, then posted time; Stars uses stars, then views, then posted time.</p>
|
<p>Sorting rules are defined in <code>list_flipnotes()</code>. Newest uses <code>posted_at DESC, id DESC</code>; Popular uses views, then stars, then posted time; Stars uses stars, then views, then posted time.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -256,7 +261,7 @@ python3 server.py</code></pre>
|
|||||||
<h3>PPM and TMB</h3>
|
<h3>PPM and TMB</h3>
|
||||||
<p>PPM is the Flipnote Studio animation container handled by <code>Hatenatools/PPM.py</code>. OSE uses the full PPM parser when it needs a decoded frame or mini-Flipnote validation. It uses <code>TMB().Read()</code> for metadata-oriented work such as FSID, username, filename and frame count. For menu thumbnails the first <code>0x6A0</code> bytes are served directly as TMB data.</p>
|
<p>PPM is the Flipnote Studio animation container handled by <code>Hatenatools/PPM.py</code>. OSE uses the full PPM parser when it needs a decoded frame or mini-Flipnote validation. It uses <code>TMB().Read()</code> for metadata-oriented work such as FSID, username, filename and frame count. For menu thumbnails the first <code>0x6A0</code> bytes are served directly as TMB data.</p>
|
||||||
<div class="docs-notice"><strong>Parser notice.</strong> Hatenatools is retained primarily for compatibility with these old file formats. OSE deliberately does not wrap it in the full set of production upload validation, signature checks, anti-abuse controls and isolation measures. Treat arbitrary files from an untrusted public upload source as untrusted input and add the controls suitable for that deployment.</div>
|
<div class="docs-notice"><strong>Parser notice.</strong> Hatenatools is retained primarily for compatibility with these old file formats. OSE deliberately does not wrap it in the full set of production upload validation, signature checks, anti-abuse controls and isolation measures. Treat arbitrary files from an untrusted public upload source as untrusted input and add the controls suitable for that deployment.</div>
|
||||||
<p><code>ppm_first_frame_image()</code> asks Hatenatools to read frames but not sound, obtains frame zero, converts the returned array in Fortran order and constructs a Pillow RGBA image. Browser thumbnails convert that image to RGB and resize with nearest-neighbour resampling.</p>
|
<p><code>ppm_first_frame_image()</code> reads frame zero without decoding sound and creates a Pillow RGBA image. Browser thumbnails use the PPM's saved thumbnail-frame index instead. Rendering respects hidden-layer flags, uses nearest-neighbour resampling and caches output against the source-file fingerprint and requested size. Mini-comment previews use their single frame. The original PPM is never rewritten for a preview.</p>
|
||||||
<h3>UGO / UGAR</h3>
|
<h3>UGO / UGAR</h3>
|
||||||
<p>Flipnote Studio menu screens are packed with Hatenatools <code>UGO</code>. <code>make_menu()</code> begins with a layout item, optionally adds top-screen title data and category/dropdown items, then encodes each button. Flipnote buttons embed TMB thumbnails; OSE navigation buttons embed generated NTFT icons. The packed result begins with the UGAR container signature used by the test suite.</p>
|
<p>Flipnote Studio menu screens are packed with Hatenatools <code>UGO</code>. <code>make_menu()</code> begins with a layout item, optionally adds top-screen title data and category/dropdown items, then encodes each button. Flipnote buttons embed TMB thumbnails; OSE navigation buttons embed generated NTFT icons. The packed result begins with the UGAR container signature used by the test suite.</p>
|
||||||
<h3>NTFT</h3>
|
<h3>NTFT</h3>
|
||||||
@@ -361,9 +366,9 @@ python3 server.py</code></pre>
|
|||||||
|
|
||||||
<section id="admin" class="docs-section">
|
<section id="admin" class="docs-section">
|
||||||
<h2>Admin and bans</h2>
|
<h2>Admin and bans</h2>
|
||||||
<p>An account reaches <code>/admin</code> only when <code>is_admin</code> is 1. OSE's admin page has two jobs: maintain <code>ip_bans</code> and soft-delete Flipnotes.</p>
|
<p>An account reaches <code>/admin</code> only when <code>is_admin</code> is 1. Its tools manage channels, server customisation, hidden Flipnotes/comments, soft deletion and exact-IP bans. Content lists are paginated and searchable. Hiding/restoring is separate from deletion; moderation reasons are administrator information.</p>
|
||||||
<p>Banning inserts or updates the exact text IP value and removes any login row for that address. The top-level router checks bans on every request, so a banned address cannot reach the browser pages, DSi resources or static content through the normal root resource.</p>
|
<p>Banning inserts or updates the exact text IP value and removes any login row for that address. The top-level router checks bans on every request, so a banned address cannot reach the browser pages, DSi resources or static content through the normal root resource.</p>
|
||||||
<p>Unban deletes the matching row. There are no subnet rules, expiry times, device bans, case queues, strike systems or hidden moderation states. The optional reason is limited to 200 characters and is only shown in the admin table.</p>
|
<p>Unban deletes the matching row. There are no subnet rules, expiry times, device bans, case queues or strike systems. The optional ban reason is limited to 200 characters and is only shown in the admin table. Normal DSi lookups and file responses exclude hidden content even when the corresponding web account is an administrator.</p>
|
||||||
<div class="docs-notice"><strong>Moderation notice.</strong> IP banning and soft deletion are intentionally much simpler than RexiMemo's private moderation system. OSE leaves out device bans, behavioural/bot detection, case tooling and other production anti-abuse logic so those systems are not disclosed in a public release. Exact-IP bans are easy to understand but can affect shared networks and can be bypassed when a user's public address changes.</div>
|
<div class="docs-notice"><strong>Moderation notice.</strong> IP banning and soft deletion are intentionally much simpler than RexiMemo's private moderation system. OSE leaves out device bans, behavioural/bot detection, case tooling and other production anti-abuse logic so those systems are not disclosed in a public release. Exact-IP bans are easy to understand but can affect shared networks and can be bypassed when a user's public address changes.</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -375,7 +380,8 @@ python3 server.py</code></pre>
|
|||||||
<tr><td><code>docs:enabled</code></td><td>off</td><td>Command-line flag enabling the built-in web documentation route and navigation item.</td></tr>
|
<tr><td><code>docs:enabled</code></td><td>off</td><td>Command-line flag enabling the built-in web documentation route and navigation item.</td></tr>
|
||||||
<tr><td>DSi proxy</td><td>server IP, port <code>8080</code></td><td>Set in the DSi connection settings. OSE is the Hatena HTTP proxy/server; DNS/auth/NAS must be supplied separately.</td></tr>
|
<tr><td>DSi proxy</td><td>server IP, port <code>8080</code></td><td>Set in the DSi connection settings. OSE is the Hatena HTTP proxy/server; DNS/auth/NAS must be supplied separately.</td></tr>
|
||||||
</tbody></table>
|
</tbody></table>
|
||||||
<p>There is no separate configuration file parser in OSE. Channel 1 and the default administrator are database seed data. DSi host names are constants in <code>reximemo.py</code>/<code>hatena.py</code>.</p>
|
<p><code>server_config.py</code> validates <code>server-settings.json</code>: name, tagline, welcome text, accent colour, logo, registration, guest posting, upload limit, listen address and port. <code>load_config()</code> supplies defaults. <code>save_config(fields)</code> merges recognised fields and atomically replaces the file only after validation. <code>REXIMEMO_CONFIG</code> selects another JSON file; <code>REXIMEMO_HOST</code> overrides its listen address. The web form changes branding and posting options. Address/port changes use setup or the file and require a restart. DSi host names remain constants.</p>
|
||||||
|
<p><code>manage.py setup</code> selects initial server/admin details. <code>manage.py check</code> reports dependencies, SQLite health and configuration. <code>manage.py backup</code> creates a portable ZIP with an online SQLite snapshot, Flipnotes, mini comments, static assets, custom logo and settings; logs are excluded. The aliases <code>--check</code> and <code>--backup</code> also work. Backups contain private account/IP records. Stop the server before restoring one.</p>
|
||||||
<div class="docs-notice"><strong>Configuration notice.</strong> OSE favours explicit, visible defaults over a production secrets/configuration stack. Do not place private keys, service tokens or live production credentials into the repository to compensate for missing configuration features. Keep deployment secrets outside the checkout and change the public seed administrator if the instance is reachable by others.</div>
|
<div class="docs-notice"><strong>Configuration notice.</strong> OSE favours explicit, visible defaults over a production secrets/configuration stack. Do not place private keys, service tokens or live production credentials into the repository to compensate for missing configuration features. Keep deployment secrets outside the checkout and change the public seed administrator if the instance is reachable by others.</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -407,7 +413,7 @@ python3 server.py</code></pre>
|
|||||||
<h3>Adding a database field</h3>
|
<h3>Adding a database field</h3>
|
||||||
<p>Extend the <code>CREATE TABLE IF NOT EXISTS</code> schema and provide an upgrade path for existing SQLite files if the field cannot be added transparently. The current schema creation code creates missing tables/indexes but is not a general migration framework. Queries return rows as plain dictionaries through <code>_row()</code>.</p>
|
<p>Extend the <code>CREATE TABLE IF NOT EXISTS</code> schema and provide an upgrade path for existing SQLite files if the field cannot be added transparently. The current schema creation code creates missing tables/indexes but is not a general migration framework. Queries return rows as plain dictionaries through <code>_row()</code>.</p>
|
||||||
<h3>Adding a channel</h3>
|
<h3>Adding a channel</h3>
|
||||||
<p>Insert a new row in <code>channels</code>. The DSi <code>ch.py</code> resource accepts any numeric channel ID present in that table. OSE's supplied home menus still post to channel 1 unless their generated URLs are changed.</p>
|
<p>Use <strong>Admin → Channels</strong> to add or edit a channel. Removal moves its Flipnotes into another explicitly selected channel; General cannot be removed. The DSi directory reads database changes on its next request, and <code>ch.py</code> accepts any existing numeric channel ID. Home-menu quick posting defaults to channel 1.</p>
|
||||||
<h3>Changing sample data</h3>
|
<h3>Changing sample data</h3>
|
||||||
<p>Keep SQLite records and files in <code>database/Creators</code> consistent. A Flipnote row requires the matching upper-case FSID directory and <code><filename>.ppm</code>. The release-shape test currently expects exactly three PPM samples.</p>
|
<p>Keep SQLite records and files in <code>database/Creators</code> consistent. A Flipnote row requires the matching upper-case FSID directory and <code><filename>.ppm</code>. The release-shape test currently expects exactly three PPM samples.</p>
|
||||||
</section>
|
</section>
|
||||||
@@ -417,7 +423,7 @@ python3 server.py</code></pre>
|
|||||||
<p>OSE is not the production RexiMemo service. The public repository does not contain Nintendo NAS/DNS/auth gateway code, certificate/private-key material, production session/device management, FSID ownership proof, PPM signature verification, emulator/bot detection, passkeys, profile pictures, Creator's Room themes, experiments, Sudomemo migration, Discord integration, support-centre flows, policy/terms pages, notifications, production API tokens, web PPM upload, advanced moderation cases or the production moderation toolset.</p>
|
<p>OSE is not the production RexiMemo service. The public repository does not contain Nintendo NAS/DNS/auth gateway code, certificate/private-key material, production session/device management, FSID ownership proof, PPM signature verification, emulator/bot detection, passkeys, profile pictures, Creator's Room themes, experiments, Sudomemo migration, Discord integration, support-centre flows, policy/terms pages, notifications, production API tokens, web PPM upload, advanced moderation cases or the production moderation toolset.</p>
|
||||||
<div class="docs-notice"><strong>Why the simplification exists.</strong> This is a deliberate release-safety boundary. Security-sensitive production systems, secrets, trust checks and anti-abuse implementation details are excluded so publishing OSE is less likely to disclose or couple itself to RexiMemo's live infrastructure. The public replacements are intentionally smaller and easier to inspect. They exist to reduce the amount of sensitive production material exposed by an open-source release, not because a simpler login, ban or verification mechanism is inherently more secure.</div>
|
<div class="docs-notice"><strong>Why the simplification exists.</strong> This is a deliberate release-safety boundary. Security-sensitive production systems, secrets, trust checks and anti-abuse implementation details are excluded so publishing OSE is less likely to disclose or couple itself to RexiMemo's live infrastructure. The public replacements are intentionally smaller and easier to inspect. They exist to reduce the amount of sensitive production material exposed by an open-source release, not because a simpler login, ban or verification mechanism is inherently more secure.</div>
|
||||||
<p>The remaining code should be read with that boundary in mind. An OSE Creator's Room is an account-or-IP ownership record; a login is an IP-to-account database row; a ban is an exact IP row; browser playback is a client-side flipnote.js player with a frame-zero fallback; and the server accepts the old proxy-style DSi HTTP path rather than reproducing the removed network/authentication stack.</p>
|
<p>The remaining code should be read with that boundary in mind. An OSE Creator's Room is an account-or-IP ownership record; a login is an IP-to-account database row; a ban is an exact IP row; browser playback is a client-side flipnote.js player with a frame-zero fallback; and the server accepts the old proxy-style DSi HTTP path rather than reproducing the removed network/authentication stack.</p>
|
||||||
<p>For public deployment work, the places most likely to need replacement or expansion are the password hashing, IP login identity, proxy/reverse-proxy IP handling, transport/authentication boundary, request-rate controls, database migrations, moderation controls, content limits/backups and operational logging. Those are outside the scope of this repository rather than hidden behind the Docs flag.</p>
|
<p>For public deployment, the reference password hashing, IP login identity, proxy/reverse-proxy IP handling, transport/authentication boundary, request-rate controls and operational logging still need review. Basic database upgrades, moderation visibility, upload limits and backups are included. The private production authentication and anti-abuse systems remain outside OSE.</p>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user
