secshare-cli 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {secshare_cli-0.2.1 → secshare_cli-0.2.2}/PKG-INFO +1 -1
- {secshare_cli-0.2.1 → secshare_cli-0.2.2}/pyproject.toml +1 -1
- {secshare_cli-0.2.1 → secshare_cli-0.2.2}/secshare_cli/cli.py +80 -17
- {secshare_cli-0.2.1 → secshare_cli-0.2.2}/.gitignore +0 -0
- {secshare_cli-0.2.1 → secshare_cli-0.2.2}/README.md +0 -0
- {secshare_cli-0.2.1 → secshare_cli-0.2.2}/secshare_cli/__init__.py +0 -0
- {secshare_cli-0.2.1 → secshare_cli-0.2.2}/secshare_cli/api.py +0 -0
- {secshare_cli-0.2.1 → secshare_cli-0.2.2}/secshare_cli/config.py +0 -0
- {secshare_cli-0.2.1 → secshare_cli-0.2.2}/secshare_cli/crypto.py +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
2
4
|
import time
|
|
3
5
|
import webbrowser
|
|
4
6
|
from urllib.parse import urlparse
|
|
@@ -125,22 +127,63 @@ def whoami():
|
|
|
125
127
|
raise click.ClickException(str(e))
|
|
126
128
|
|
|
127
129
|
|
|
130
|
+
def _copy_to_clipboard(text: str) -> None:
|
|
131
|
+
if sys.platform == "darwin":
|
|
132
|
+
subprocess.run(["pbcopy"], input=text.encode(), check=True)
|
|
133
|
+
elif sys.platform == "win32":
|
|
134
|
+
subprocess.run(["clip"], input=text.encode(), check=True)
|
|
135
|
+
else:
|
|
136
|
+
try:
|
|
137
|
+
subprocess.run(["xclip", "-selection", "clipboard"], input=text.encode(), check=True)
|
|
138
|
+
except FileNotFoundError:
|
|
139
|
+
subprocess.run(["xsel", "--clipboard", "--input"], input=text.encode(), check=True)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _schedule_clipboard_clear(seconds: int) -> None:
|
|
143
|
+
"""Launch a detached process that clears the clipboard after `seconds`. Returns immediately."""
|
|
144
|
+
if sys.platform == "darwin":
|
|
145
|
+
cmd = f"sleep {seconds} && echo -n '' | pbcopy"
|
|
146
|
+
elif sys.platform == "win32":
|
|
147
|
+
cmd = None # handled separately
|
|
148
|
+
else:
|
|
149
|
+
cmd = f"sleep {seconds} && echo -n '' | xclip -selection clipboard 2>/dev/null || echo -n '' | xsel --clipboard --input 2>/dev/null"
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
if sys.platform == "win32":
|
|
153
|
+
subprocess.Popen(
|
|
154
|
+
["powershell", "-Command", f"Start-Sleep {seconds}; Set-Clipboard ''"],
|
|
155
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
|
156
|
+
creationflags=subprocess.DETACHED_PROCESS, # type: ignore[attr-defined]
|
|
157
|
+
)
|
|
158
|
+
else:
|
|
159
|
+
subprocess.Popen(
|
|
160
|
+
["bash", "-c", cmd],
|
|
161
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
|
162
|
+
start_new_session=True,
|
|
163
|
+
)
|
|
164
|
+
except Exception:
|
|
165
|
+
pass # best-effort
|
|
166
|
+
|
|
167
|
+
|
|
128
168
|
@cli.command()
|
|
129
169
|
@click.argument("link")
|
|
130
|
-
@click.option("--show", is_flag=True, help="Print plaintext to terminal
|
|
131
|
-
|
|
170
|
+
@click.option("--show", is_flag=True, help="Print plaintext to terminal.")
|
|
171
|
+
@click.option("--clip", is_flag=True, help="Copy to clipboard. Clears after 30s.")
|
|
172
|
+
def get(link, show, clip):
|
|
132
173
|
"""Fetch and decrypt a secret.
|
|
133
174
|
|
|
134
175
|
\b
|
|
135
|
-
Inject .env
|
|
176
|
+
Inject a .env file into your shell (recommended):
|
|
136
177
|
eval "$(secshare get https://secshare.link/s/abc123#KEY)"
|
|
137
178
|
|
|
138
179
|
\b
|
|
139
|
-
|
|
180
|
+
Copy a secret to clipboard:
|
|
181
|
+
secshare get https://secshare.link/s/abc123#KEY --clip
|
|
182
|
+
|
|
183
|
+
\b
|
|
184
|
+
Print explicitly:
|
|
140
185
|
secshare get https://secshare.link/s/abc123#KEY --show
|
|
141
186
|
"""
|
|
142
|
-
import sys
|
|
143
|
-
|
|
144
187
|
try:
|
|
145
188
|
secret_id, key_fragment = _parse_link(link)
|
|
146
189
|
data = fetch_secret(secret_id)
|
|
@@ -150,23 +193,43 @@ def get(link, show):
|
|
|
150
193
|
except Exception as e:
|
|
151
194
|
raise click.ClickException(str(e))
|
|
152
195
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
" To inject into your shell: eval \"$(secshare get <link>)\"\n"
|
|
157
|
-
" To print explicitly: secshare get <link> --show"
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
# .env payload — output KEY=VALUE lines
|
|
196
|
+
# Detect payload type
|
|
197
|
+
secret_type = "secret"
|
|
198
|
+
content = plaintext
|
|
161
199
|
try:
|
|
162
200
|
parsed = json.loads(plaintext)
|
|
163
201
|
if isinstance(parsed, dict) and parsed.get("__secshare_type") == "env":
|
|
164
|
-
|
|
165
|
-
|
|
202
|
+
secret_type = "env"
|
|
203
|
+
content = parsed["content"]
|
|
166
204
|
except (json.JSONDecodeError, AttributeError):
|
|
167
205
|
pass
|
|
168
206
|
|
|
169
|
-
|
|
207
|
+
# --clip: copy silently regardless of TTY
|
|
208
|
+
if clip:
|
|
209
|
+
try:
|
|
210
|
+
_copy_to_clipboard(content)
|
|
211
|
+
except Exception as e:
|
|
212
|
+
raise click.ClickException(f"Clipboard unavailable: {e}")
|
|
213
|
+
_schedule_clipboard_clear(30)
|
|
214
|
+
click.echo("Copied to clipboard. Clears in 30s.", err=True)
|
|
215
|
+
return
|
|
216
|
+
|
|
217
|
+
# TTY guard
|
|
218
|
+
if sys.stdout.isatty() and not show:
|
|
219
|
+
if secret_type == "env":
|
|
220
|
+
raise click.ClickException(
|
|
221
|
+
"Refusing to print secret to terminal.\n"
|
|
222
|
+
" To inject into your shell: eval \"$(secshare get <link>)\"\n"
|
|
223
|
+
" To print explicitly: secshare get <link> --show"
|
|
224
|
+
)
|
|
225
|
+
else:
|
|
226
|
+
raise click.ClickException(
|
|
227
|
+
"Refusing to print secret to terminal.\n"
|
|
228
|
+
" To copy to clipboard: secshare get <link> --clip\n"
|
|
229
|
+
" To print explicitly: secshare get <link> --show"
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
click.echo(content, nl=False)
|
|
170
233
|
|
|
171
234
|
|
|
172
235
|
@cli.command()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|