repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

pico / pipe / html
Eric Bower · 01 Dec 24

marketing.page.tmpl

  1{{template "base" .}}
  2
  3{{define "title"}}pipe: authenticated pubsub over ssh{{end}}
  4
  5{{define "meta"}}
  6<meta name="description" content="authenticated *nix pipes over ssh" />
  7
  8<meta property="og:type" content="website">
  9<meta property="og:site_name" content="{{.Site.Domain}}">
 10<meta property="og:url" content="https://{{.Site.Domain}}">
 11<meta property="og:title" content="{{.Site.Domain}}">
 12<meta property="og:description" content="pubsub using ssh">
 13{{end}}
 14
 15{{define "attrs"}}class="container-sm"{{end}}
 16
 17{{define "body"}}
 18<header class="flex flex-col items-center gap-2">
 19  <div class="flex flex-col">
 20    <img src="https://pico.sh/logo.svg" alt="pico logo" width="50" height="50" />
 21    <canvas id="canvas" width="50" height="50"></canvas>
 22    <hr width="100%" class="m-0" />
 23  </div>
 24  <h1 class="text-2xl font-bold text-center">Authenticated *nix pipes over ssh</h1>
 25</header>
 26
 27<article class="flex flex-col gap-2">
 28  <div>
 29    <p>
 30      The simplest authenticated pubsub system.  Send messages through
 31      user-defined topics (aka channels).  By default, topics are private to the authenticated
 32      ssh user.  The default pubsub model is multicast with bidirectional
 33      blocking, meaning a publisher (<code>pub</code>) will send its message to all
 34      subscribers (<code>sub</code>) for a topic.  There can be many publishers
 35      and many subscribers on a topic. Further, both <code>pub</code> and
 36      <code>sub</code> will wait for at least one event to be sent or received on the topic.
 37    </p>
 38
 39    <h2 class="text-lg">Features</h2>
 40
 41    <ol>
 42      <li>Familiar *nix pipes API</li>
 43      <li>Zero-install</li>
 44      <li>Authenticated pubsub using ssh</li>
 45      <li>Private pubsub by default</li>
 46      <li>Public pubsub by topic (opt-in)</li>
 47      <li>Multicast (many pubs to many subs)</li>
 48      <li>Bidirectional (e.g. chat)</li>
 49      <li>Paradigms for connecting to a topic:
 50        <ol>
 51          <li>Read (<code>sub</code>)</li>
 52          <li>Write (<code>pub</code>)</li>
 53          <li>Read & Write (<code>pipe</code>)</li>
 54        </ol>
 55      </li>
 56    </ol>
 57  </div>
 58
 59  <div>
 60    <h2 class="text-xl">A basic API</h2>
 61    <p>Pipe some data into our ssh app and we will send it to anyone listening.</p>
 62    <pre>ssh {{.Site.Domain}} sub mykey</pre>
 63    <pre>echo "hello world!" | ssh {{.Site.Domain}} pub mykey</pre>
 64
 65    <details>
 66      <summary>Demo</summary>
 67      <script
 68        src="https://asciinema.org/a/679717.js"
 69        id="asciicast-679717"
 70        async="true"
 71        data-theme="dracula"
 72        data-loop="true"
 73        data-speed="1.5"
 74        data-idle-time-limit="2"
 75      ></script>
 76    </details>
 77  </div>
 78
 79  <div>
 80    <h2 class="text-xl">Simple desktop notifications</h2>
 81    <p>Want to quickly receive a notification when a job is done?  It can be as simple as:</p>
 82    <pre>ssh {{.Site.Domain}} sub notify; notify-send "job done!"</pre>
 83    <pre>./longjob.sh; ssh {{.Site.Domain}} pub notify -e</pre>
 84  </div>
 85
 86  <div>
 87    <h2 class="text-xl">File sharing</h2>
 88    <p>Sometimes you need data exfiltration and all you have is SSH:</p>
 89    <pre>cat doc.md | ssh {{.Site.Domain}} pub thedoc</pre>
 90    <pre>ssh {{.Site.Domain}} sub thedoc > ./important.md</pre>
 91
 92    <details>
 93      <summary>Demo</summary>
 94      <script
 95        src="https://asciinema.org/a/679715.js"
 96        id="asciicast-679715"
 97        async="true"
 98        data-theme="dracula"
 99        data-loop="true"
100        data-speed="1.5"
101        data-idle-time-limit="2"
102      ></script>
103    </details>
104  </div>
105
106  <div>
107    <h2 class="text-xl">Pipe command output</h2>
108    <p>
109      Send command output through our <code>pipe</code> command.  The
110      <code>pipe</code> command is just like <code>pub</code> except it
111      is non-blocking and also acts like a <code>sub</code>.  So a client
112      that can read and write to the topic.
113    </p>
114    <pre>ssh {{.Site.Domain}} sub htop</pre>
115    <pre>htop | ssh {{.Site.Domain}} pipe htop</pre>
116
117    <details>
118      <summary>Demo</summary>
119      <script
120        src="https://asciinema.org/a/679712.js"
121        id="asciicast-679712"
122        async="true"
123        data-theme="dracula"
124        data-loop="true"
125        data-speed="1.5"
126        data-idle-time-limit="2"
127      ></script>
128    </details>
129  </div>
130
131  <div>
132    <h2 class="text-xl">Chat</h2>
133    <p>Use our <code>pipe</code> command to have a chat with someone.</p>
134    <pre>ssh {{.Site.Domain}} pipe mychan -p</pre>
135    <p>
136      Now anyone with a <code>pico</code> account can subscribe to this
137      topic using the same command and start typing!
138    </p>
139
140    <details>
141      <summary>Demo</summary>
142      <script
143        src="https://asciinema.org/a/679709.js"
144        id="asciicast-679709"
145        async="true"
146        data-theme="dracula"
147        data-loop="true"
148        data-speed="1.5"
149        data-idle-time-limit="2"
150      ></script>
151    </details>
152  </div>
153
154  <div>
155    <h2 class="text-xl">Pipe reverse shell</h2>
156    <p>If you squint hard enough you can give users interactive access to your shell.</p>
157    <pre>mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | ssh {{.Site.Domain}} pipe myshell > /tmp/f</pre>
158    <pre>ssh {{.Site.Domain}} pipe myshell</pre>
159
160    <details>
161      <summary>Demo</summary>
162      <script
163        src="https://asciinema.org/a/679704.js"
164        id="asciicast-679704"
165        async="true"
166        data-theme="dracula"
167        data-loop="true"
168        data-speed="1.5"
169        data-idle-time-limit="2"
170      ></script>
171    </details>
172  </div>
173
174  <div>
175    <h2 class="text-xl">Simple CI/CD</h2>
176    <p>
177      I'm always looking for easy ways to simplify deploying apps
178      automatically.  Having an authenticated, zero-install event system
179      seems handy for this purpose.
180    </p>
181    <pre>while true; do ssh {{.Site.Domain}} sub deploy-app; docker compose pull && docker compose up -d; done</pre>
182    <pre>docker buildx build --push -t myapp .; ssh {{.Site.Domain}} pub deploy-app -e</pre>
183  </div>
184
185  <div>
186    <h2 class="text-xl">Pubsub interactions</h2>
187
188    <h3 class="text-lg">Multiple subs</h3>
189    <p>
190      Have many subscribers, they will all receive the message.
191    </p>
192    <pre>ssh {{.Site.Domain}} sub foobar</pre>
193    <pre>ssh {{.Site.Domain}} sub foobar</pre>
194    <pre>while true; do echo "foobar1"; sleep 1; done | ssh {{.Site.Domain}} pub foobar</pre>
195
196    <details>
197      <summary>Demo</summary>
198      <script
199        src="https://asciinema.org/a/679699.js"
200        id="asciicast-679699"
201        async="true"
202        data-theme="dracula"
203        data-loop="true"
204        data-speed="1.5"
205        data-idle-time-limit="2"
206      ></script>
207    </details>
208
209    <h3 class="text-lg">Multiple pubs</h3>
210    <p>Have many publishers send messages to subscribers.</p>
211    <pre>while true; do echo "foobar1"; sleep 1; done | ssh {{.Site.Domain}} pub foobar</pre>
212    <pre>while true; do echo "foobar2"; sleep 1; done | ssh {{.Site.Domain}} pub foobar</pre>
213    <pre>ssh {{.Site.Domain}} sub foobar</pre>
214
215    <details>
216      <summary>Demo</summary>
217      <script
218        src="https://asciinema.org/a/679698.js"
219        id="asciicast-679698"
220        async="true"
221        data-theme="dracula"
222        data-loop="true"
223        data-speed="1.5"
224        data-idle-time-limit="2"
225      ></script>
226    </details>
227
228    <h3 class="text-lg">Multiple pubs and subs</h3>
229    <p>Have many publishers send messages to many subscribers.</p>
230    <pre>ssh {{.Site.Domain}} sub foobar</pre>
231    <pre>ssh {{.Site.Domain}} sub foobar</pre>
232    <pre>while true; do echo "foobar1"; sleep 1; done | ssh {{.Site.Domain}} pub foobar</pre>
233    <pre>while true; do echo "foobar2"; sleep 1; done | ssh {{.Site.Domain}} pub foobar</pre>
234
235    <details>
236      <summary>Demo</summary>
237      <script
238        src="https://asciinema.org/a/679694.js"
239        id="asciicast-679694"
240        async="true"
241        data-theme="dracula"
242        data-loop="true"
243        data-speed="1.5"
244        data-idle-time-limit="2"
245      ></script>
246    </details>
247  </div>
248
249  <div>
250    <h2 class="text-xl">Send a public message</h2>
251    <pre>echo "hello world!" | ssh {{.Site.Domain}} pub mychan -p</pre>
252    <p>Now anyone with a <code>pico</code> account can subscribe to this topic:</p>
253    <pre>ssh {{.Site.Domain}} sub mychan -p</pre>
254  </div>
255
256  <div>
257    <h2 class="text-xl">Caveats</h2>
258    <p>
259      You must always pipe something into <code>pub</code> or else it will block
260      indefinitely until the process is killed.  However, you can provide a
261      flag to send an empty message: <code>pub xyz -e</code>.
262    </p>
263  </div>
264
265  <div>
266    <h2 class="text-xl">Inspiration</h2>
267    <p>
268      A special thanks to <a href="https://patchbay.pub">patchbay.pub</a> for our inspiration.
269    </p>
270  </div>
271
272  <div>
273    <h2 class="text-xl">Latest posts</h2>
274    <div class="flex items-center">
275      <div class="mr font-italic">2024-10-06</div>
276      <div><a href="https://blog.pico.sh/ann-022-pubsub">pipe: our pubsub ssh service</a></div>
277    </div>
278  </div>
279
280  <div class="text-center mb-2">
281    <p>built on our <a href="https://github.com/picosh/pubsub">go pkg</a>.</p>
282    <a href="https://pico.sh/getting-started" class="btn-link inline-block">GET STARTED</a>
283  </div>
284</article>
285
286{{template "marketing-footer" .}}
287{{end}}