OctoPrint-BitBang 0.2.7__tar.gz → 0.2.8__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.
Files changed (34) hide show
  1. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8/OctoPrint_BitBang.egg-info}/PKG-INFO +11 -3
  2. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/OctoPrint_BitBang.egg-info/SOURCES.txt +2 -1
  3. {octoprint_bitbang-0.2.7/OctoPrint_BitBang.egg-info → octoprint_bitbang-0.2.8}/PKG-INFO +11 -3
  4. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/README.md +10 -2
  5. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/_plugin.py +150 -0
  6. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/bin/bitbang-linux-amd64 +0 -0
  7. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/bin/bitbang-linux-arm64 +0 -0
  8. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/bin/bitbang-linux-armv7 +0 -0
  9. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/static/js/bitbang.js +52 -0
  10. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/templates/bitbang_settings.jinja2 +19 -2
  11. octoprint_bitbang-0.2.8/octoprint_bitbang/templates/bitbang_wizard.jinja2 +47 -0
  12. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/pyproject.toml +1 -1
  13. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/LICENSE +0 -0
  14. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/MANIFEST.in +0 -0
  15. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/OctoPrint_BitBang.egg-info/dependency_links.txt +0 -0
  16. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/OctoPrint_BitBang.egg-info/entry_points.txt +0 -0
  17. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/OctoPrint_BitBang.egg-info/requires.txt +0 -0
  18. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/OctoPrint_BitBang.egg-info/top_level.txt +0 -0
  19. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/__init__.py +0 -0
  20. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/__main__.py +0 -0
  21. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/app.py +0 -0
  22. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/camera.py +0 -0
  23. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/flip_track.py +0 -0
  24. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/index.html +0 -0
  25. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/octoprint_adapter.py +0 -0
  26. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/pi_camera_track.py +0 -0
  27. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/pi_h264_source.py +0 -0
  28. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/static/favicon.png +0 -0
  29. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/templates/bitbang_navbar.jinja2 +0 -0
  30. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/templates/bitbang_webcam.jinja2 +0 -0
  31. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/usb_camera_source.py +0 -0
  32. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/octoprint_bitbang/v4l2_h264_source.py +0 -0
  33. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/setup.cfg +0 -0
  34. {octoprint_bitbang-0.2.7 → octoprint_bitbang-0.2.8}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: OctoPrint-BitBang
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: Remote OctoPrint access with live H.264 video via BitBang WebRTC
5
5
  Author-email: Rich LeGrand <rich.m.legrand@gmail.com>
6
6
  License-Expression: MIT
@@ -115,12 +115,20 @@ All settings live in **Settings → BitBang**:
115
115
  | Setting | Effect |
116
116
  |---|---|
117
117
  | Enabled | Toggle BitBang remote access |
118
- | PIN | Optional 4+ digit PIN prompt on the remote URL |
118
+ | PIN | **Required by default.** At least 4 characters; prompted on the remote URL. Remote access stays **off** until a PIN is set (or "Allow no PIN" is ticked). |
119
+ | Allow no PIN | Expose remote access with no PIN (not recommended — anyone with the link can control the printer) |
119
120
  | Camera | Auto-detect, or select from dropdown list |
120
121
  | Resolution | VGA → HD (depending on what selected camera supports) |
121
122
  | Flip horizontal / vertical | Flip video if necessary |
122
123
 
123
- All settings take effect on OctoPrint restart. Full-screen button and brightness slider are overlaid on the video window (Control tab) and update immediately.
124
+ Changes to the PIN and Enabled settings take effect immediately (no OctoPrint restart). Full-screen button and brightness slider are overlaid on the video window (Control tab) and update immediately.
125
+
126
+ ### Set a PIN (required)
127
+
128
+ BitBang exposes a public link to your printer, so it is protected by a PIN. On
129
+ first install a **setup wizard** prompts you to choose one — remote access does
130
+ not start until you do (fail-closed). You can change it any time under
131
+ **Settings → BitBang**.
124
132
 
125
133
  ## How it works
126
134
 
@@ -28,4 +28,5 @@ octoprint_bitbang/static/favicon.png
28
28
  octoprint_bitbang/static/js/bitbang.js
29
29
  octoprint_bitbang/templates/bitbang_navbar.jinja2
30
30
  octoprint_bitbang/templates/bitbang_settings.jinja2
31
- octoprint_bitbang/templates/bitbang_webcam.jinja2
31
+ octoprint_bitbang/templates/bitbang_webcam.jinja2
32
+ octoprint_bitbang/templates/bitbang_wizard.jinja2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: OctoPrint-BitBang
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: Remote OctoPrint access with live H.264 video via BitBang WebRTC
5
5
  Author-email: Rich LeGrand <rich.m.legrand@gmail.com>
6
6
  License-Expression: MIT
@@ -115,12 +115,20 @@ All settings live in **Settings → BitBang**:
115
115
  | Setting | Effect |
116
116
  |---|---|
117
117
  | Enabled | Toggle BitBang remote access |
118
- | PIN | Optional 4+ digit PIN prompt on the remote URL |
118
+ | PIN | **Required by default.** At least 4 characters; prompted on the remote URL. Remote access stays **off** until a PIN is set (or "Allow no PIN" is ticked). |
119
+ | Allow no PIN | Expose remote access with no PIN (not recommended — anyone with the link can control the printer) |
119
120
  | Camera | Auto-detect, or select from dropdown list |
120
121
  | Resolution | VGA → HD (depending on what selected camera supports) |
121
122
  | Flip horizontal / vertical | Flip video if necessary |
122
123
 
123
- All settings take effect on OctoPrint restart. Full-screen button and brightness slider are overlaid on the video window (Control tab) and update immediately.
124
+ Changes to the PIN and Enabled settings take effect immediately (no OctoPrint restart). Full-screen button and brightness slider are overlaid on the video window (Control tab) and update immediately.
125
+
126
+ ### Set a PIN (required)
127
+
128
+ BitBang exposes a public link to your printer, so it is protected by a PIN. On
129
+ first install a **setup wizard** prompts you to choose one — remote access does
130
+ not start until you do (fail-closed). You can change it any time under
131
+ **Settings → BitBang**.
124
132
 
125
133
  ## How it works
126
134
 
@@ -85,12 +85,20 @@ All settings live in **Settings → BitBang**:
85
85
  | Setting | Effect |
86
86
  |---|---|
87
87
  | Enabled | Toggle BitBang remote access |
88
- | PIN | Optional 4+ digit PIN prompt on the remote URL |
88
+ | PIN | **Required by default.** At least 4 characters; prompted on the remote URL. Remote access stays **off** until a PIN is set (or "Allow no PIN" is ticked). |
89
+ | Allow no PIN | Expose remote access with no PIN (not recommended — anyone with the link can control the printer) |
89
90
  | Camera | Auto-detect, or select from dropdown list |
90
91
  | Resolution | VGA → HD (depending on what selected camera supports) |
91
92
  | Flip horizontal / vertical | Flip video if necessary |
92
93
 
93
- All settings take effect on OctoPrint restart. Full-screen button and brightness slider are overlaid on the video window (Control tab) and update immediately.
94
+ Changes to the PIN and Enabled settings take effect immediately (no OctoPrint restart). Full-screen button and brightness slider are overlaid on the video window (Control tab) and update immediately.
95
+
96
+ ### Set a PIN (required)
97
+
98
+ BitBang exposes a public link to your printer, so it is protected by a PIN. On
99
+ first install a **setup wizard** prompts you to choose one — remote access does
100
+ not start until you do (fail-closed). You can change it any time under
101
+ **Settings → BitBang**.
94
102
 
95
103
  ## How it works
96
104
 
@@ -47,6 +47,12 @@ except ImportError as e:
47
47
  )
48
48
 
49
49
 
50
+ # A PIN must be empty (remote access then gated/off) or at least this many
51
+ # characters. Mirrored by the wizard/settings JS; enforced server-side in
52
+ # on_settings_save as the authoritative backstop.
53
+ MIN_PIN_LENGTH = 4
54
+
55
+
50
56
  class BitBangPlugin(
51
57
  octoprint.plugin.StartupPlugin,
52
58
  octoprint.plugin.ShutdownPlugin,
@@ -55,12 +61,14 @@ class BitBangPlugin(
55
61
  octoprint.plugin.AssetPlugin,
56
62
  octoprint.plugin.BlueprintPlugin,
57
63
  octoprint.plugin.WebcamProviderPlugin,
64
+ octoprint.plugin.WizardPlugin,
58
65
  ):
59
66
  def __init__(self):
60
67
  super().__init__()
61
68
  self._adapter = None
62
69
  self._thread = None
63
70
  self._local_pcs = set() # track local WebRTC peer connections
71
+ self._running = False # whether the remote-access proxy is live
64
72
 
65
73
  def on_shutdown(self):
66
74
  # Release the camera cleanly when OctoPrint shuts down via its own
@@ -93,8 +101,30 @@ class BitBangPlugin(
93
101
  if not self._settings.get_boolean(["enabled"]):
94
102
  self._logger.info("BitBang disabled in settings")
95
103
  return
104
+ if not self._remote_access_allowed():
105
+ self._logger.warning(
106
+ "BitBang: remote access NOT started — no PIN is set. Set a PIN "
107
+ "in the BitBang settings (or, advanced, explicitly allow running "
108
+ "without one) to enable remote access."
109
+ )
110
+ return
96
111
  self._start_bitbang()
97
112
 
113
+ def _remote_access_allowed(self):
114
+ """Secure-by-default gate. The public tunnel is only exposed when a
115
+ PIN protects it, or the user has explicitly opted into running without
116
+ one. An empty PIN with no opt-in means remote access stays OFF — this
117
+ is the enforcement behind the setup wizard (which merely prompts).
118
+
119
+ Without this, anyone holding the share URL reaches OctoPrint with no
120
+ BitBang-layer auth; for users who enabled OctoPrint's autologinLocal
121
+ that is a full remote takeover (see the X-Forwarded-For handling in
122
+ the Go proxy)."""
123
+ pin = (self._settings.get(["pin"]) or "").strip()
124
+ if pin:
125
+ return True
126
+ return self._settings.get_boolean(["allow_no_pin"])
127
+
98
128
  def _probe_picamera2_sensor(self):
99
129
  # Cache before the adapter opens the camera — picamera2 can't be
100
130
  # opened twice, so the resolutions endpoint relies on this.
@@ -209,6 +239,7 @@ class BitBangPlugin(
209
239
  # pion) owns the transport under our shared identity, and our camera
210
240
  # track is fed into a video PeerConnection over a socketpair relay.
211
241
  self._start_video_bridge()
242
+ self._running = True
212
243
 
213
244
  def _run_aiortc_loop(self):
214
245
  """Bare asyncio loop for aiortc. Replaces the adapter's own bitbang
@@ -334,6 +365,39 @@ class BitBangPlugin(
334
365
  time.sleep(backoff)
335
366
  backoff = min(backoff * 2, 30)
336
367
 
368
+ def _stop_bitbang(self):
369
+ """Tear down the remote-access proxy (Go subprocess supervisor +
370
+ aiortc loop + camera). Best-effort; each step is independently
371
+ guarded so a failure in one doesn't strand the others."""
372
+ self._running = False
373
+ # Tell the supervisor not to respawn, then kill the current proxy.
374
+ self._go_stop = True
375
+ proc = getattr(self, "_go_proc", None)
376
+ if proc is not None and proc.poll() is None:
377
+ try:
378
+ proc.terminate()
379
+ except Exception:
380
+ pass
381
+ # Release the camera.
382
+ try:
383
+ player = getattr(self._adapter, "player", None) if self._adapter else None
384
+ if player is not None:
385
+ player.stop()
386
+ except Exception as e:
387
+ self._logger.warning(f"BitBang: error stopping camera: {e}")
388
+ # Stop the aiortc event loop so its thread can exit.
389
+ try:
390
+ loop = getattr(self._adapter, "_loop", None) if self._adapter else None
391
+ if loop is not None and loop.is_running():
392
+ loop.call_soon_threadsafe(loop.stop)
393
+ except Exception:
394
+ pass
395
+ self._adapter = None
396
+ # Clear the persisted URL so the navbar doesn't show a dead link.
397
+ self._settings.set(["url"], "")
398
+ self._settings.save()
399
+ self._plugin_manager.send_plugin_message(self._identifier, {"url": ""})
400
+
337
401
  # -- Local WebRTC video signaling --
338
402
 
339
403
  @octoprint.plugin.BlueprintPlugin.route("/ice-servers", methods=["GET"])
@@ -756,6 +820,9 @@ class BitBangPlugin(
756
820
  return {
757
821
  "enabled": True,
758
822
  "pin": "",
823
+ # Explicit opt-in to expose remote access with NO PIN. Default
824
+ # False so a fresh install is gated until the wizard runs.
825
+ "allow_no_pin": False,
759
826
  "url": "",
760
827
  "camera_device": "",
761
828
  "camera_resolution": "640x480",
@@ -765,16 +832,99 @@ class BitBangPlugin(
765
832
  "signaling_server": "bitba.ng",
766
833
  }
767
834
 
835
+ def on_settings_save(self, data):
836
+ # Server-side PIN-policy backstop. The wizard/settings JS validates
837
+ # too, but this is authoritative: a non-empty PIN below the minimum
838
+ # length is rejected (the prior value is kept) rather than persisted.
839
+ if data.get("pin"):
840
+ pin = str(data["pin"]).strip()
841
+ if 0 < len(pin) < MIN_PIN_LENGTH:
842
+ self._logger.warning(
843
+ "BitBang: rejected PIN shorter than %d characters",
844
+ MIN_PIN_LENGTH,
845
+ )
846
+ data["pin"] = self._settings.get(["pin"])
847
+ else:
848
+ data["pin"] = pin
849
+
850
+ # Snapshot gate-relevant state, save, then reconcile if it changed so
851
+ # the wizard's "set a PIN" takes effect without an OctoPrint restart.
852
+ before = self._gate_state()
853
+ octoprint.plugin.SettingsPlugin.on_settings_save(self, data)
854
+ if self._gate_state() != before:
855
+ self._reconcile_remote_access()
856
+
857
+ def _gate_state(self):
858
+ """The tuple of settings that determines whether/how the proxy runs."""
859
+ return (
860
+ self._settings.get_boolean(["enabled"]),
861
+ (self._settings.get(["pin"]) or "").strip(),
862
+ self._settings.get_boolean(["allow_no_pin"]),
863
+ )
864
+
865
+ def _reconcile_remote_access(self):
866
+ """Bring the running proxy in line with current settings. Best-effort
867
+ and defensive: on any failure the user can still restart OctoPrint to
868
+ pick up the change (the prior behavior)."""
869
+ if _VIDEO_IMPORT_ERROR:
870
+ return # video stack unavailable; nothing to start/stop
871
+ try:
872
+ should_run = self._settings.get_boolean(["enabled"]) and self._remote_access_allowed()
873
+ if should_run and not self._running:
874
+ self._logger.info("BitBang: remote access now permitted — starting")
875
+ self._start_bitbang()
876
+ elif not should_run and self._running:
877
+ self._logger.info("BitBang: remote access no longer permitted — stopping")
878
+ self._stop_bitbang()
879
+ elif should_run and self._running:
880
+ # Still running, but the PIN may have changed. The Go proxy
881
+ # reads -pin fresh on each spawn, so bouncing the subprocess
882
+ # (the supervisor respawns it) applies the new PIN.
883
+ self._logger.info("BitBang: PIN/config changed — restarting proxy")
884
+ self._restart_go_proxy()
885
+ except Exception as e:
886
+ self._logger.warning(
887
+ "BitBang: live reconcile failed (%s); restart OctoPrint to apply", e
888
+ )
889
+
890
+ def _restart_go_proxy(self):
891
+ """Bounce just the Go subprocess; the supervisor loop respawns it with
892
+ the current -pin. Falls back to a full restart if no proc is tracked."""
893
+ proc = getattr(self, "_go_proc", None)
894
+ if proc is not None and proc.poll() is None:
895
+ proc.terminate()
896
+ else:
897
+ self._stop_bitbang()
898
+ if self._settings.get_boolean(["enabled"]) and self._remote_access_allowed():
899
+ self._start_bitbang()
900
+
768
901
  def get_template_configs(self):
769
902
  return [
770
903
  {"type": "settings", "custom_bindings": True},
771
904
  {"type": "navbar", "custom_bindings": True},
905
+ {"type": "wizard", "name": "BitBang", "template": "bitbang_wizard.jinja2"},
772
906
  # Render the live view as a proper webcam provider template so
773
907
  # OctoPrint shows it only when "BitBang Camera" is the selected
774
908
  # webcam -- no DOM-replacing the classic webcam.
775
909
  {"type": "webcam", "name": "BitBang Camera", "template": "bitbang_webcam.jinja2"},
776
910
  ]
777
911
 
912
+ # -- Setup wizard (secure-by-default PIN prompt) --
913
+
914
+ def is_wizard_required(self):
915
+ # Show the wizard whenever remote access would be enabled but is
916
+ # currently ungated (no PIN, no explicit opt-out). Covers fresh
917
+ # installs and existing no-PIN users on upgrade.
918
+ return self._settings.get_boolean(["enabled"]) and not self._remote_access_allowed()
919
+
920
+ def get_wizard_version(self):
921
+ # Bump to re-show the wizard to users who already cleared an older
922
+ # version (e.g. if the PIN policy changes again).
923
+ return 1
924
+
925
+ def get_wizard_details(self):
926
+ return {"required": self.is_wizard_required()}
927
+
778
928
  def get_template_vars(self):
779
929
  return {"plugin_version": __plugin_version__}
780
930
 
@@ -399,3 +399,55 @@ OCTOPRINT_VIEWMODELS.push({
399
399
  dependencies: ["settingsViewModel"],
400
400
  elements: ["#navbar_plugin_bitbang", "#settings_plugin_bitbang"]
401
401
  });
402
+
403
+ /*
404
+ * Setup-wizard viewmodel. The wizard fields bind directly to the shared
405
+ * settings observables, so OctoPrint persists them on Finish (which then
406
+ * runs the server-side PIN-length backstop in on_settings_save). This VM
407
+ * only supplies live validation feedback for the PIN field.
408
+ */
409
+ function BitBangWizardViewModel(parameters) {
410
+ var self = this;
411
+ self.settings = parameters[0];
412
+
413
+ function bb() {
414
+ var plugins = self.settings.settings.plugins;
415
+ return plugins && plugins.bitbang ? plugins.bitbang : null;
416
+ }
417
+
418
+ function pinOk() {
419
+ var b = bb();
420
+ if (!b) return true;
421
+ return b.allow_no_pin() || (b.pin() || "").trim().length >= 4;
422
+ }
423
+
424
+ self.pinTooShort = ko.pureComputed(function () {
425
+ var b = bb();
426
+ if (!b) return false;
427
+ var pin = (b.pin() || "").trim();
428
+ return pin.length > 0 && pin.length < 4;
429
+ });
430
+
431
+ // Set once the user tries to finish without a usable PIN. Drives the
432
+ // blocking message; clears reactively once they set a valid PIN or
433
+ // tick the no-PIN opt-out.
434
+ self.finishAttempted = ko.observable(false);
435
+ self.finishBlocked = ko.pureComputed(function () {
436
+ return self.finishAttempted() && !pinOk();
437
+ });
438
+
439
+ // Veto the wizard's Finish button unless a valid PIN is set (or the user
440
+ // explicitly opted out). Returning false keeps the dialog open — see
441
+ // OctoPrint wizard.js onBeforeWizardFinish.
442
+ self.onBeforeWizardFinish = function () {
443
+ if (pinOk()) return true;
444
+ self.finishAttempted(true);
445
+ return false;
446
+ };
447
+ }
448
+
449
+ OCTOPRINT_VIEWMODELS.push({
450
+ construct: BitBangWizardViewModel,
451
+ dependencies: ["settingsViewModel"],
452
+ elements: ["#wizard_plugin_bitbang"]
453
+ });
@@ -14,8 +14,25 @@
14
14
  <div class="controls">
15
15
  <input type="text" class="input-medium"
16
16
  data-bind="value: settings.settings.plugins.bitbang.pin"
17
- placeholder="Empty to disable">
18
- <span class="help-inline">Optional PIN to protect remote access</span>
17
+ placeholder="At least 4 characters">
18
+ <span class="help-inline">
19
+ Protects remote access. At least 4 characters. Leave empty
20
+ only if you tick &ldquo;allow no PIN&rdquo; below &mdash;
21
+ otherwise remote access stays disabled.
22
+ </span>
23
+ </div>
24
+ </div>
25
+
26
+ <div class="control-group">
27
+ <div class="controls">
28
+ <label class="checkbox">
29
+ <input type="checkbox"
30
+ data-bind="checked: settings.settings.plugins.bitbang.allow_no_pin">
31
+ Allow remote access without a PIN (not recommended)
32
+ </label>
33
+ <span class="help-block muted">
34
+ Anyone who has the share link could control this printer.
35
+ </span>
19
36
  </div>
20
37
  </div>
21
38
 
@@ -0,0 +1,47 @@
1
+ <div id="wizard_plugin_bitbang">
2
+ <h3>Secure your BitBang remote access</h3>
3
+ <p>
4
+ BitBang gives this OctoPrint a private link you can use to reach it from
5
+ anywhere. Protect that link with a PIN so only you can connect &mdash; we
6
+ recommend at least {{ 4 }} characters.
7
+ </p>
8
+
9
+ <form class="form-horizontal">
10
+ <div class="control-group">
11
+ <label class="control-label">PIN</label>
12
+ <div class="controls">
13
+ <input type="text" class="input-medium"
14
+ data-bind="value: settings.settings.plugins.bitbang.pin, valueUpdate: 'afterkeydown'"
15
+ placeholder="At least 4 characters">
16
+ <span class="help-inline" style="color: #b94a48;"
17
+ data-bind="visible: pinTooShort">
18
+ PIN must be at least 4 characters.
19
+ </span>
20
+ </div>
21
+ </div>
22
+
23
+ <div class="control-group">
24
+ <div class="controls">
25
+ <label class="checkbox">
26
+ <input type="checkbox"
27
+ data-bind="checked: settings.settings.plugins.bitbang.allow_no_pin">
28
+ Advanced: run without a PIN
29
+ </label>
30
+ <span class="help-block muted">
31
+ Not recommended &mdash; anyone who has the link could control
32
+ this printer.
33
+ </span>
34
+ </div>
35
+ </div>
36
+ </form>
37
+
38
+ <p class="muted">
39
+ Until you set a PIN (or tick the box above), BitBang remote access stays
40
+ disabled.
41
+ </p>
42
+
43
+ <div class="alert alert-error" data-bind="visible: finishBlocked" style="display: none;">
44
+ Set a PIN of at least 4 characters, or tick &ldquo;run without a
45
+ PIN&rdquo; above, before finishing.
46
+ </div>
47
+ </div>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "OctoPrint-BitBang"
7
- version = "0.2.7"
7
+ version = "0.2.8"
8
8
  description = "Remote OctoPrint access with live H.264 video via BitBang WebRTC"
9
9
  readme = "README.md"
10
10
  license = "MIT"