Antonio Mika
·
2025-03-12
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 <div class="text-center flex gap">
26 <a href="https://pico.sh/getting-started" class="btn-link mt inline-block">GET STARTED</a>
27 <a href="https://pico.sh/pipe" class="btn-link mt inline-block">DOCS</a>
28 </div>
29</header>
30
31<article class="flex flex-col gap-2">
32 <div>
33 <p>
34 The simplest authenticated pubsub system. Send messages through
35 user-defined topics (aka channels). By default, topics are private to the authenticated
36 ssh user. The default pubsub model is multicast with bidirectional
37 blocking, meaning a publisher (<code>pub</code>) will send its message to all
38 subscribers (<code>sub</code>) for a topic. There can be many publishers
39 and many subscribers on a topic. Further, both <code>pub</code> and
40 <code>sub</code> will wait for at least one event to be sent or received on the topic.
41 </p>
42
43 <h2 class="text-lg">Features</h2>
44
45 <ol>
46 <li>Familiar *nix pipes API</li>
47 <li>Zero-install</li>
48 <li>Authenticated pubsub using ssh</li>
49 <li>Private pubsub by default</li>
50 <li>Public pubsub by topic (opt-in)</li>
51 <li>Multicast (many pubs to many subs)</li>
52 <li>Bidirectional (e.g. chat)</li>
53 <li>Paradigms for connecting to a topic:
54 <ol>
55 <li>Read (<code>sub</code>)</li>
56 <li>Write (<code>pub</code>)</li>
57 <li>Read & Write (<code>pipe</code>)</li>
58 </ol>
59 </li>
60 </ol>
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 class="text-center mb-2">
261 <a href="https://pico.sh/getting-started" class="btn-link inline-block">GET STARTED</a>
262 </div>
263</article>
264
265{{template "marketing-footer" .}}
266{{end}}