193e74b02e187180320b9d5621f540402dcd2334 — Benthor 2 months ago 5d1c993 master
bugfix, helper script
4 files changed, 161 insertions(+), 1 deletions(-)

A documents/attic/index.gmi
R documents/{inimeg.gmi => attic/specification.gmi}
M internal/gemini/header.go
A scripts/inimeg.sh
A documents/attic/index.gmi => documents/attic/index.gmi +74 -0
@@ 0,0 1,74 @@
As of July 2022, these pages are considered "archived" and won't be maintained any longer

=> ../index.gmi Home

# What the hell is Inimeg?

Inimeg is an entirely optional extension for Gemini. It is intended as a way for Gemini clients to upload content to Gemini servers in-band, i.e., without reliance on other protocols like FTP, SSH or even dedicated HTML forms.

The Inimeg mechanism allows a Gemini client to temporarily act as a Gemini server, with the Gemini server briefly playing the part of a Gemini client. Entirely within an otherwise standard Gemini transaction, a server and client can agree to swap roles, with the server then waiting for any content that the client may send (i.e., "upload") to the server.

Inimeg strictly follows the Gemini spec and only extends it in three respects.

* The "inimeg://" URL scheme, used by a Gemini client for an Inimeg "upload" request
* The 7X range of status code, sent by a Gemini server in response to an Inimeg request
* The Inimeg transaction, a Gemini transaction with partial role reversal

Inimeg is careful not break or be in conflict with the current Gemini spec.

=> specification.gmi See the Inimeg speculative specification for further details

## Credit

Inimeg was first proposed informally on the Gemini mailing list by Sean Connor (spc) and Petite Abeille before I was even aware of Geminis existence. My consolation price is the knowledge that all the stuff I came up with on my own is apparently not completely silly.

(The mailing list thread in question can no longer be found)

## Trying it out

The server running this site is by no means a reference implementation of the spec, but it already supports the 77 REFLECT status code.

There is a playground space under the /playground subdirectory on this server. Feel free to play around with it.

The following is a minimal example how to leave a message on the server using socat for ssl handling:

sh -c 'echo -en "inimeg://inimeg.space/playground/fnord.gmi\r\n";
       sleep 1;
       echo -en "20 text/gemini\r\nHello World!"' | \
socat - ssl:inimeg.space:1965,verify=0

### Nota Bene
Since no authentication is required for the Playground, it's anarchy down there. Especially /playground/index.gmi might or might not be currently defaced, redirect elsewhere or fail to render in your client.

=> gemini://inimeg.space/playground/ Inimeg-enabled landing area (might or might not be currently defaced or redirect elsewhere)

Why don't you leave me a note under your favourite namespace? 

=> gemini://inimeg.space/playground/correct/horse/battery/staple/hi.gmi Example for a note to me that might not get so easily defaced

Why don't you write a thin script that backs up your gemlog to the playground somewhere? Then drop me an email and tell me about your experiences.

Finally, an explicit invitation to submit something via inimeg might look like this:

=> inimeg://inimeg.space/playground/guestbook/42dead1337beef23.gmi Link with explicit Inimeg URL scheme

Leave me a Note :-)

## Contact

Discussions about this proposal are likely to happen on the Gemini
mailing list. I'm happy to take suggestions and corrections by direct
email as well.

=> https://lists.orbitalfox.eu/listinfo/gemini Gemini mailing list
=> mailto:benthor@posteo.de Contact me directly at <benthor@posteo.de>
=> https://chaos.social/@benthor Fediverse: @benthor@chaos.social
=> inimeg://inimeg.space/playground/guestbook/obfuscate-this-yourself/message.gmi Inimeg Guestbook

R documents/inimeg.gmi => documents/attic/specification.gmi +0 -0
M internal/gemini/header.go => internal/gemini/header.go +1 -1
@@ 54,7 54,7 @@ func ReadHeader(r io.Reader) (*Header, error) {
	h := &Header{
		StatusCode: statusCode,
		Meta:       hdr[i+1:],
		Meta:       hdr[i+1 : l-2],
	h.reader = strings.NewReader(h.String())
	return h, nil

A scripts/inimeg.sh => scripts/inimeg.sh +86 -0
@@ 0,0 1,86 @@
#!/usr/bin/env bash

set -ueo pipefail

function usage {
    echo "usage: ${0} -f FILE -u URL [-c CERT] [-d]"
    echo ""
    echo "         -f FILE   FILE to upload (mandatory)"
    echo "         -u URL    inimeg URL to upload FILE to (mandatory)"
    echo "         -c CERT   optional CERT to identify with for uploading"
    echo "         -d        don't upload anything, but diff remote file"
    echo "                   at URL against FILE"

function headerfile {
    MIME=$(file -b --mime-type ${FILE})
    if [ ${MIME} = "text/plain" ] && echo ${FILE} | grep -Eq "\.gmi$"
    echo -ne "20 ${MIME}\r\n"
    cat ${FILE}

function request {
    echo -ne "${URL}\r\n"
    sleep 1
    headerfile ${FILE}

function get {
    HOST=$(echo $1 | sed -e 's|inimeg://\([^/]*\).*$|\1|')
    echo $1 | sed -e 's|^inimeg:|gemini:|' | socat - ssl:${HOST}:1965,verify=0

function send {
    HOST=$(echo ${URL} | sed -e 's|inimeg://\([^/]*\).*$|\1|')
    if [[ ${CERT} = "!NONE!" ]]
        socat - ssl:${HOST}:1965,verify=0
        socat - ssl:${HOST}:1965,verify=0,cert=${CERT}


while getopts dc:f:u:h flag
    case ${flag} in
        h) usage; exit 0;;
        c) cert=${OPTARG};;
        f) file=${OPTARG};;
        u) url=${OPTARG};;
        d) diff=1;;
            echo "${0}: Must supply an argument to -${OPTARG}." >&2
            exit 1

if [[ ${#} -lt 2 ]]
    exit 1


#diff -u1 <(headerfile ${file}) <(get ${url}) | tee >(grep -E '^-' | wc -l | sed -e "s|^|${file} in |") >(grep -E '^+' | wc -l |sed -e 's|^|out |') > /dev/null
if [[ ${diff} -eq 1 ]]
    diff -u <(get ${url}) <(headerfile ${file})
    request ${url} ${file} | send ${url} ${cert} ${diff}