Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ Available separately at: https://github.com/sccn/liblsl

COMPONENT LICENSING POLICY

Incorporated components retain their original licenses. Where a component was released under the MIT License, it remains under the MIT License in this Repository; the same applies to components under the ISC License, the Boost Software License, or a public-domain dedication. Their verbatim notices are reproduced in THIRD-PARTY-NOTICES.md in the repository root, and each component directory retains its own license file.
Incorporated components retain their original licenses. Where a component was released under the MIT License, it remains under the MIT License in this Repository; the same applies to components under the ISC License, the Boost Software License, the GNU General Public License, or a public-domain dedication. A component under a copyleft license (for example the GNU GPL) is aggregated with the other contents of this Repository within the meaning of that license, and is not brought under these proprietary terms; its own license governs it in full. Their verbatim notices are reproduced in THIRD-PARTY-NOTICES.md in the repository root, and each component directory retains its own license file.

Client applications and language bindings distributed as components of this Repository, together with the integration code added to them, are made available under the license of the upstream project each derives from, not under the proprietary terms of this license. That integration code consists of interface declarations and status-display logic that call the public library API; it contains no cryptographic implementation.

Expand Down
11 changes: 11 additions & 0 deletions THIRD-PARTY-NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ THE SOFTWARE.

---

## SigVisualizer (GNU General Public License v3.0)

Signal-display application, vendored as a component at `apps/SigVisualizer/`.
Unlike the other components, its upstream is GPLv3, so this component and the
security integration added to it are GPLv3. The full license text is at
`apps/SigVisualizer/LICENSE`; it is not inlined here because of its length.
The component is aggregated with the rest of this repository under GPLv3
section 5 and is not subject to the proprietary Secure LSL terms.

---

## asio (Boost Software License 1.0)

Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
Expand Down
3 changes: 3 additions & 0 deletions apps/SigVisualizer/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__pycache__/
.idea/
venv/
39 changes: 39 additions & 0 deletions apps/SigVisualizer/COMPONENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# SigVisualizer component

The SigVisualizer signal-display application with security-status support,
vendored into this monorepo as a component.

## Licensing (GPLv3, unlike the MIT components)

Upstream SigVisualizer is licensed under the GNU General Public License v3.0.
This component therefore remains GPLv3; see `LICENSE` in this directory. Because
GPLv3 is copyleft, the security integration added here is also GPLv3, and it
could not be relicensed under proprietary terms even though it contains no
cryptography (it reads stream security status through the public LSL API).

This is a deliberate departure from the pylsl and LabRecorder components, whose
upstreams are MIT. The component sits in this repository as an aggregate under
GPLv3 section 5; the proprietary Secure LSL license does not extend to it. See
COMPONENT LICENSING POLICY in the repository-root `LICENSE`.

## Note for review

SigVisualizer imports the in-repo `pylsl` component and, at the user's runtime,
loads `liblsl-secure` (proprietary) through `ctypes`. Whether distributing a
GPLv3 application alongside a proprietary library it loads at runtime creates
any obligation is a question for UCSD OIC rather than one resolved here; it is
the same question that already applies to the drop-in library-replacement route.
Co-location itself is mere aggregation under GPLv3 section 5.

## Upstream tracking

- Upstream: https://github.com/labstreaminglayer/App-SigVisualizer
- Based on upstream commit: `aa754e6`
- Security integration: `lsl_security_helper.py` (a pylsl compatibility shim),
security-status display in `paintwidget.py`, and mismatch detection

## Behavior against a stock liblsl

The security queries are optional. Against a stock `liblsl` that does not export
them, the helper reports security unavailable and the application runs as
upstream does.
674 changes: 674 additions & 0 deletions apps/SigVisualizer/LICENSE

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions apps/SigVisualizer/LSL_sender.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import time
from random import random as rand
from pylsl import StreamInfo, StreamOutlet

info = StreamInfo('BioSemi', 'EEG', 8, 100, 'float32', 'myuid34234')
outlet = StreamOutlet(info)

print("now sending data...")
while True:
mysample = [rand(), rand(), rand(), rand(), rand(), rand(), rand(), rand()]
outlet.push_sample(mysample)
time.sleep(0.01)
21 changes: 21 additions & 0 deletions apps/SigVisualizer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# SigVisualizer

SigVisualizer is a PyQt5 GUI application that visualizes electroencephalogram signals streamed from [__lab streaming layer__ (LSL)](https://github.com/sccn/labstreaminglayer "LabStreamingLayer (LSL)") in real time.

## Requirements
* Python 3.x
* PyQt5

![image](SigVisualizer_demo.gif)

## License

GNU General Public License v3.0; see [LICENSE](LICENSE).

This component is the [SigVisualizer](https://github.com/labstreaminglayer/App-SigVisualizer)
application with security-status support added, distributed as a component of
the Secure LSL monorepo. Its upstream is GPLv3, so this component remains GPLv3,
and the security integration added here (which reads stream security status
through the public LSL API and contains no cryptographic implementation) is
likewise GPLv3. It is aggregated with the other components under GPLv3 section 5;
see COMPONENT LICENSING POLICY in the repository-root LICENSE.
Binary file added apps/SigVisualizer/SigVisualizer_demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/SigVisualizer/createUI.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"C:\Users\Yida Lin\AppData\Local\Programs\Python\Python37\Scripts\pyuic5.exe" -x ui_sigvisualizer.ui -o ui_sigvisualizer.py
4 changes: 4 additions & 0 deletions apps/SigVisualizer/icons/chevron_left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions apps/SigVisualizer/icons/chevron_right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
127 changes: 127 additions & 0 deletions apps/SigVisualizer/lsl_security_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
"""
Helper module to add security API support to pylsl.

This module ensures security_enabled() and security_fingerprint() methods
are available on pylsl.StreamInfo, and provides local_security_enabled()
to check if the local device has security credentials configured.

Either uses native pylsl support (pylsl >= TBD with secure-lsl-support branch)
or patches the class.

Usage:
import lsl_security_helper # Import before using pylsl
import pylsl

# Check local security status
if lsl_security_helper.local_security_enabled():
print("Local security credentials are configured")

streams = pylsl.resolve_streams()
for s in streams:
if s.security_enabled():
print(f"Stream {s.name()} is encrypted: {s.security_fingerprint()}")
"""

import ctypes
import pylsl
from pylsl.lib import lib


def _check_native_support():
"""Check if pylsl has native security_enabled/security_fingerprint methods."""
return (
hasattr(pylsl.StreamInfo, "security_enabled")
and hasattr(pylsl.StreamInfo, "security_fingerprint")
and callable(getattr(pylsl.StreamInfo, "security_enabled", None))
)


def _setup_security_functions():
"""Set up ctypes declarations for security functions."""
try:
# lsl_get_security_enabled returns int32_t (1=enabled, 0=disabled, -1=error)
lib.lsl_get_security_enabled.restype = ctypes.c_int32
lib.lsl_get_security_enabled.argtypes = [ctypes.c_void_p]

# lsl_get_security_fingerprint returns const char*
lib.lsl_get_security_fingerprint.restype = ctypes.c_char_p
lib.lsl_get_security_fingerprint.argtypes = [ctypes.c_void_p]

return True
except AttributeError:
# Functions not available in this liblsl build
return False


def _setup_local_security_function():
"""Set up ctypes declaration for local security enabled check."""
try:
# lsl_local_security_enabled returns int32_t (1=enabled, 0=disabled)
lib.lsl_local_security_enabled.restype = ctypes.c_int32
lib.lsl_local_security_enabled.argtypes = []
return True
except AttributeError:
return False


# Track if local security function is available
_local_security_available = _setup_local_security_function()


def local_security_enabled() -> bool:
"""Check if the local device has security credentials configured.

Returns True if security credentials are loaded and enabled locally,
False otherwise (either not a secure build or no credentials configured).
"""
if not _local_security_available:
return False
try:
return lib.lsl_local_security_enabled() == 1
except Exception:
return False


def _security_enabled(self) -> bool:
"""Check if the stream has security/encryption enabled.

Returns True if security is enabled, False otherwise.
"""
try:
result = lib.lsl_get_security_enabled(self.obj)
return result == 1
except Exception:
return False


def _security_fingerprint(self) -> str:
"""Get the security fingerprint of the stream's public key.

Returns the fingerprint string (SHA256:xxxx...) or empty string if
security is not enabled.
"""
try:
result = lib.lsl_get_security_fingerprint(self.obj)
if result:
return result.decode("utf-8")
return ""
except Exception:
return ""


# Check for native support first (pylsl with secure-lsl-support branch)
if _check_native_support():
# pylsl already has native support; no patching needed
_security_available = True
else:
# No native support; try to patch StreamInfo class
_security_available = _setup_security_functions()

if _security_available:
pylsl.StreamInfo.security_enabled = _security_enabled
pylsl.StreamInfo.security_fingerprint = _security_fingerprint
else:
# Provide stub methods that always return False/empty
pylsl.StreamInfo.security_enabled = lambda self: False
pylsl.StreamInfo.security_fingerprint = lambda self: ""
print("Warning: Security API not available in liblsl. Using stub methods.")
Loading
Loading