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 · 22 Oct 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>Configurable blocking characteristics for <code>pub</code></li>
 50      <li>Configurable timeout for <code>pub</code></li>
 51      <li>Paradigms for connecting to a topic:
 52        <ol>
 53          <li>Read (<code>sub</code>)</li>
 54          <li>Write (<code>pub</code>)</li>
 55          <li>Read & Write (<code>pipe</code>)</li>
 56        </ol>
 57      </li>
 58    </ol>
 59
 60    <blockquote>This service is undergoing active development, expect bugs, feature dev, and server restarts</blockquote>
 61  </div>
 62
 63  <div>
 64    <h2 class="text-xl">A basic API</h2>
 65    <p>Pipe some data into our ssh app and we will send it to anyone listening.</p>
 66    <pre>ssh {{.Site.Domain}} sub mykey</pre>
 67    <pre>echo "hello world!" | ssh {{.Site.Domain}} pub mykey</pre>
 68
 69    <details>
 70      <summary>Demo</summary>
 71      <script
 72        src="https://asciinema.org/a/679717.js"
 73        id="asciicast-679717"
 74        async="true"
 75        data-theme="dracula"
 76        data-loop="true"
 77        data-speed="1.5"
 78        data-idle-time-limit="2"
 79      ></script>
 80    </details>
 81  </div>
 82
 83  <div>
 84    <h2 class="text-xl">Simple desktop notifications</h2>
 85    <p>Want to quickly receive a notification when a job is done?  It can be as simple as:</p>
 86    <pre>ssh {{.Site.Domain}} sub notify; notify-send "job done!"</pre>
 87    <pre>./longjob.sh; ssh {{.Site.Domain}} pub notify -e</pre>
 88  </div>
 89
 90  <div>
 91    <h2 class="text-xl">File sharing</h2>
 92    <p>Sometimes you need data exfiltration and all you have is SSH:</p>
 93    <pre>cat doc.md | ssh {{.Site.Domain}} pub thedoc</pre>
 94    <pre>ssh {{.Site.Domain}} sub thedoc > ./important.md</pre>
 95
 96    <details>
 97      <summary>Demo</summary>
 98      <script
 99        src="https://asciinema.org/a/679715.js"
100        id="asciicast-679715"
101        async="true"
102        data-theme="dracula"
103        data-loop="true"
104        data-speed="1.5"
105        data-idle-time-limit="2"
106      ></script>
107    </details>
108  </div>
109
110  <div>
111    <h2 class="text-xl">Pipe command output</h2>
112    <p>
113      Send command output through our <code>pipe</code> command.  The
114      <code>pipe</code> command is just like <code>pub</code> except it
115      is non-blocking and also acts like a <code>sub</code>.  So a client
116      that can read and write to the topic.
117    </p>
118    <pre>ssh {{.Site.Domain}} sub htop</pre>
119    <pre>htop | ssh {{.Site.Domain}} pipe htop</pre>
120
121    <details>
122      <summary>Demo</summary>
123      <script
124        src="https://asciinema.org/a/679712.js"
125        id="asciicast-679712"
126        async="true"
127        data-theme="dracula"
128        data-loop="true"
129        data-speed="1.5"
130        data-idle-time-limit="2"
131      ></script>
132    </details>
133  </div>
134
135  <div>
136    <h2 class="text-xl">Chat</h2>
137    <p>Use our <code>pipe</code> command to have a chat with someone.</p>
138    <pre>ssh {{.Site.Domain}} pipe mychan -p</pre>
139    <p>
140      Now anyone with a <code>pico</code> account can subscribe to this
141      topic using the same command and start typing!
142    </p>
143
144    <details>
145      <summary>Demo</summary>
146      <script
147        src="https://asciinema.org/a/679709.js"
148        id="asciicast-679709"
149        async="true"
150        data-theme="dracula"
151        data-loop="true"
152        data-speed="1.5"
153        data-idle-time-limit="2"
154      ></script>
155    </details>
156  </div>
157
158  <div>
159    <h2 class="text-xl">Pipe reverse shell</h2>
160    <p>If you squint hard enough you can give users interactive access to your shell.</p>
161    <pre>mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | ssh {{.Site.Domain}} pipe myshell > /tmp/f</pre>
162    <pre>ssh {{.Site.Domain}} pipe myshell</pre>
163
164    <details>
165      <summary>Demo</summary>
166      <script
167        src="https://asciinema.org/a/679704.js"
168        id="asciicast-679704"
169        async="true"
170        data-theme="dracula"
171        data-loop="true"
172        data-speed="1.5"
173        data-idle-time-limit="2"
174      ></script>
175    </details>
176  </div>
177
178  <div>
179    <h2 class="text-xl">Simple CI/CD</h2>
180    <p>
181      I'm always looking for easy ways to simplify deploying apps
182      automatically.  Having an authenticated, zero-install event system
183      seems handy for this purpose.
184    </p>
185    <pre>while true; do ssh {{.Site.Domain}} sub deploy-app; docker compose pull && docker compose up -d; done</pre>
186    <pre>docker buildx build --push -t myapp .; ssh {{.Site.Domain}} pub deploy-app -e</pre>
187  </div>
188
189  <div>
190    <h2 class="text-xl">Pubsub interactions</h2>
191
192    <h3 class="text-lg">Multiple subs</h3>
193    <p>
194      Have many subscribers, they will all receive the message.
195    </p>
196    <pre>ssh {{.Site.Domain}} sub foobar</pre>
197    <pre>ssh {{.Site.Domain}} sub foobar</pre>
198    <pre>while true; do echo "foobar1"; sleep 1; done | ssh {{.Site.Domain}} pub foobar</pre>
199
200    <details>
201      <summary>Demo</summary>
202      <script
203        src="https://asciinema.org/a/679699.js"
204        id="asciicast-679699"
205        async="true"
206        data-theme="dracula"
207        data-loop="true"
208        data-speed="1.5"
209        data-idle-time-limit="2"
210      ></script>
211    </details>
212
213    <h3 class="text-lg">Multiple pubs</h3>
214    <p>Have many publishers send messages to subscribers.</p>
215    <pre>while true; do echo "foobar1"; sleep 1; done | ssh {{.Site.Domain}} pub foobar</pre>
216    <pre>while true; do echo "foobar2"; sleep 1; done | ssh {{.Site.Domain}} pub foobar</pre>
217    <pre>ssh {{.Site.Domain}} sub foobar</pre>
218
219    <details>
220      <summary>Demo</summary>
221      <script
222        src="https://asciinema.org/a/679698.js"
223        id="asciicast-679698"
224        async="true"
225        data-theme="dracula"
226        data-loop="true"
227        data-speed="1.5"
228        data-idle-time-limit="2"
229      ></script>
230    </details>
231
232    <h3 class="text-lg">Multiple pubs and subs</h3>
233    <p>Have many publishers send messages to many subscribers.</p>
234    <pre>ssh {{.Site.Domain}} sub foobar</pre>
235    <pre>ssh {{.Site.Domain}} sub foobar</pre>
236    <pre>while true; do echo "foobar1"; sleep 1; done | ssh {{.Site.Domain}} pub foobar</pre>
237    <pre>while true; do echo "foobar2"; sleep 1; done | ssh {{.Site.Domain}} pub foobar</pre>
238
239    <details>
240      <summary>Demo</summary>
241      <script
242        src="https://asciinema.org/a/679694.js"
243        id="asciicast-679694"
244        async="true"
245        data-theme="dracula"
246        data-loop="true"
247        data-speed="1.5"
248        data-idle-time-limit="2"
249      ></script>
250    </details>
251  </div>
252
253  <div>
254    <h2 class="text-xl">Send a public message</h2>
255    <pre>echo "hello world!" | ssh {{.Site.Domain}} pub mychan -p</pre>
256    <p>Now anyone with a <code>pico</code> account can subscribe to this topic:</p>
257    <pre>ssh {{.Site.Domain}} sub mychan -p</pre>
258  </div>
259
260  <div>
261    <h2 class="text-xl">Caveats</h2>
262    <p>
263      You must always pipe something into <code>pub</code> or else it will block
264      indefinitely until the process is killed.  However, you can provide a
265      flag to send an empty message: <code>pub xyz -e</code>.
266    </p>
267  </div>
268
269  <div>
270    <h2 class="text-xl">Inspiration</h2>
271    <p>
272      A special thanks to <a href="https://patchbay.pub">patchbay.pub</a> for our inspiration.
273    </p>
274  </div>
275
276  <div>
277    <h2 class="text-xl">Latest posts</h2>
278    <div class="flex items-center">
279      <div class="mr font-italic">2024-10-06</div>
280      <div><a href="https://blog.pico.sh/pubsub">pipe: our pubsub ssh service</a></div>
281    </div>
282  </div>
283
284  <div class="text-center mb-2">
285    <p>built on our <a href="https://github.com/picosh/pubsub">go pkg</a>.</p>
286    <a href="https://pico.sh/getting-started" class="btn-link inline-block">GET STARTED</a>
287  </div>
288</article>
289
290{{template "marketing-footer" .}}
291{{end}}