diff --git a/.github/workflows/build_docker.yml b/.github/workflows/build_docker.yml deleted file mode 100644 index 2fc43967..00000000 --- a/.github/workflows/build_docker.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Docker Image CI - -on: - workflow_dispatch: - push: - tags: - - tbd -# - tc_nightly -# - tc_v*.*.* -# pull_request: -# branches: [ "master", "develop" ] - -jobs: - build-amd64: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - name: Build Docker amd64 image - run: docker buildx build --platform linux/amd64 . --tag revvox/teddycloud-amd64:$(date +%s) --tag revvox/teddycloud:latest - build-arm64: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - with: - platforms: arm64 - - name: Build Docker arm64 image - run: docker buildx build --platform linux/arm64 . --tag revvox/teddycloud-arm64:$(date +%s) --tag revvox/teddycloud-arm64:latest - build-arm: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - with: - platforms: arm - - name: Build Docker arm image - run: docker buildx build --platform linux/arm . --tag revvox/teddycloud-arm:$(date +%s) --tag revvox/teddycloud-arm:latest - build-s390x: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - with: - platforms: s390x - - name: Build Docker s390x image - run: docker buildx build --platform linux/s390x . --tag revvox/teddycloud-s390x:$(date +%s) --tag revvox/teddycloud-s390x:latest diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 71e1cf94..5dedeacd 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -101,6 +101,11 @@ jobs: draft: true prerelease: ${{ env.IS_PRERELEASE }} if: github.event_name != 'pull_request' + + - uses: actions/upload-artifact@master + with: + name: release.zip + path: ./install/zip/release.zip - name: Upload Release Asset id: upload-release-asset diff --git a/.github/workflows/build_release_multiarch.yml b/.github/workflows/build_release_multiarch.yml deleted file mode 100644 index 8cb0b6c4..00000000 --- a/.github/workflows/build_release_multiarch.yml +++ /dev/null @@ -1,169 +0,0 @@ -name: Build and zip - -on: - push: - tags: - - tbd -# Makefile for other arch -# - tc_nightly -# - tc_v* - -jobs: - build-amd64: - runs-on: ubuntu-latest - outputs: - upload_url: ${{ steps.set_data1.outputs.upload_url }} - appendix: ${{ steps.set_data2.outputs.appendix }} - steps: - - name: Get current datetime - id: get-datetime - run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - - - name: Set templates for nightly - id: set-templates-nightly - if: startsWith(github.ref, 'refs/tags/tc_nightly') - run: | - echo "TAG_NAME=${GITHUB_REF#refs/tags/}_${{ env.CURRENT_DATE }}_${{ github.run_number }}" >> $GITHUB_ENV - echo "RELEASE_NAME=Nightly ${{ env.CURRENT_DATE }} - Run ID ${{ github.run_number }}" >> $GITHUB_ENV - echo "ASSET_APPENDIX=nightly_${{ env.CURRENT_DATE }}.${{ github.run_number }}" >> $GITHUB_ENV - echo "IS_PRERELEASE=true" >> $GITHUB_ENV - - - name: Set templates for release and delete trigger tag - id: set-templates-release - if: startsWith(github.ref, 'refs/tags/tc_v') - run: | - echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV - echo "RELEASE_NAME=Release ${GITHUB_REF#refs/tags/hbng_bl_}" >> $GITHUB_ENV - echo "ASSET_APPENDIX=release_${GITHUB_REF#refs/tags/hbng_bl_}" >> $GITHUB_ENV - echo "IS_PRERELEASE=false" >> $GITHUB_ENV - - - uses: actions/checkout@v2 - with: - submodules: recursive - - - name: Build and zip amd64 - id: build-zip - run: make zip - - name: Check amd64 release zip existence - id: check_release - uses: andstor/file-existence-action@v1 - with: - files: "./install/zip/release.zip" - allow_failure: true - - name: File exist - if: steps.check_files.outputs.files_exists == 'true' - run: echo amd64 release zip exists! - - - name: Create Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ env.TAG_NAME }} - release_name: Teddy Cloud ${{ env.RELEASE_NAME }} - draft: true - prerelease: ${{ env.IS_PRERELEASE }} - - - name: Upload Release Asset - id: upload-release-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: ./install/zip/release.zip - asset_name: teddy_cloud.amd64.${{ env.ASSET_APPENDIX }}.zip - asset_content_type: application/zip - - id: set_data1 - run: echo "upload_url=${{ steps.create_release.outputs.upload_url }}" >> "$GITHUB_OUTPUT" - - id: set_data2 - run: echo "appendix=${{ env.ASSET_APPENDIX }}" >> "$GITHUB_OUTPUT" - - build-arm64: - runs-on: ubuntu-latest - needs: build-amd64 - steps: - - uses: actions/checkout@v3 - - name: Build and zip arm64 - id: build-zip - run: make zip - - name: Check arm64 release zip existence - id: check_release - uses: andstor/file-existence-action@v1 - with: - files: "./install/zip/release.zip" - allow_failure: true - - name: File exist - if: steps.check_files.outputs.files_exists == 'true' - run: echo amd64 release zip exists! - - - name: Upload Release Asset - id: upload-release-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.build-amd64.outputs.upload_url }} - asset_path: ./install/zip/release.zip - asset_name: teddy_cloud.arm64.${{ needs.build-amd64.outputs.appendix }}.zip - asset_content_type: application/zip - - build-arm: - runs-on: ubuntu-latest - needs: build-amd64 - steps: - - uses: actions/checkout@v3 - - name: Build and zip arm - id: build-zip - run: make zip - - name: Check arm release zip existence - id: check_release - uses: andstor/file-existence-action@v1 - with: - files: "./install/zip/release.zip" - allow_failure: true - - name: File exist - if: steps.check_files.outputs.files_exists == 'true' - run: echo amd64 release zip exists! - - - name: Upload Release Asset - id: upload-release-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.build-amd64.outputs.upload_url }} - asset_path: ./install/zip/release.zip - asset_name: teddy_cloud.arm.${{ needs.build-amd64.outputs.appendix }}.zip - asset_content_type: application/zip - - build-s390x: - runs-on: ubuntu-latest - needs: build-amd64 - steps: - - uses: actions/checkout@v3 - - name: Build and zip s390x - id: build-zip - run: make zip - - name: Check s390x release zip existence - id: check_release - uses: andstor/file-existence-action@v1 - with: - files: "./install/zip/release.zip" - allow_failure: true - - name: File exist - if: steps.check_files.outputs.files_exists == 'true' - run: echo amd64 release zip exists! - - - name: Upload Release Asset - id: upload-release-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.build-amd64.outputs.upload_url }} - asset_path: ./install/zip/release.zip - asset_name: teddy_cloud.s390x.${{ needs.build-amd64.outputs.appendix }}.zip - asset_content_type: application/zip - \ No newline at end of file diff --git a/.github/workflows/build_release_test.yml b/.github/workflows/build_release_test.yml index 6223627f..efe4c3d8 100644 --- a/.github/workflows/build_release_test.yml +++ b/.github/workflows/build_release_test.yml @@ -1,4 +1,4 @@ -name: Build and zip windows/linux +name: Build and zip windows/linux Test on: workflow_dispatch: @@ -16,12 +16,13 @@ jobs: - name: Build windows id: build-zip - run: make build + run: cmd /c "C:\"Program Files"\"Microsoft Visual Studio"\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat && make build PLATFORM=windows SHELL_ENV=bash" + shell: cmd - name: Check windows executable existence id: check_release uses: andstor/file-existence-action@v1 with: - files: "./bin/teddybench.exe" + files: "bin/teddycloud.exe" allow_failure: false - name: File exist if: steps.check_files.outputs.files_exists == 'true' @@ -29,10 +30,11 @@ jobs: - uses: actions/upload-artifact@master with: name: windows-exe - path: /bin/teddybench.exe + path: bin\* build-linux-amd64: + needs: build-windows-amd64 runs-on: ubuntu-latest outputs: upload_url: ${{ steps.set_data1.outputs.upload_url }} @@ -68,7 +70,7 @@ jobs: - uses: actions/download-artifact@master with: name: windows-exe - path: /bin/teddybench.exe + path: ./bin/ - name: Build and zip amd64 id: build-zip diff --git a/.gitignore b/.gitignore index d695ade7..8573d0b3 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ contrib/certs/server/teddy-key.pem contrib/certs/client/teddy-cert.pem contrib/certs/client/teddy-key.csr contrib/certs/client/teddy-key.pem +.vs/ +SSLKEYLOGFILE diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..c5d8f7c2 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,22 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "windowsSdkVersion": "10.0.22000.0", + "compilerPath": "cl.exe", + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "windows-msvc-x64", + "configurationProvider": "ms-vscode.makefile-tools" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 3bc4e9bc..f631b839 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,7 +1,7 @@ { "configurations": [ { - "name": "Launch Server", + "name": "[linux] teddyCloud", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/bin/teddycloud", @@ -16,7 +16,7 @@ }, }, { - "name": "Launch Cloud Time Test", + "name": "[linux] teddyCloud Time Test", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/bin/teddycloud", @@ -31,6 +31,46 @@ "linux": { "MIMode": "gdb", }, + }, + { + "name": "[wsl] teddyCloud", + "type": "cppdbg", + "request": "launch", + "program": "bin/teddycloud", + "args": [], + "cwd": ".", + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "pipeTransport": { + "pipeProgram": "wsl", + "pipeArgs": [ "--cd", "${workspaceFolder}", "-e", "bash", "-c" ] + }, + "preLaunchTask": "[wsl] build", + "logging": { + "programOutput": true, + "engineLogging": true, + "trace": false, + "traceResponse": false, + "exceptions": false + } + }, + { + "name": "[win32] teddyCloud", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/bin/teddycloud.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/", + "environment": [], + "externalConsole": true, + "preLaunchTask": "[win32] build" } ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e900c1ba..05879eff 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -11,13 +11,23 @@ "options": { "cwd": "${workspaceRoot}" }, + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": [ + "/C", + // The path to VsDevCmd.bat depends on the version of Visual Studio you have installed. + "\"C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/Common7/Tools/VsDevCmd.bat\"", + "&&" + ] + } + } + }, "tasks": [ { "label": "build", - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "command": "make build", "type": "shell", "problemMatcher": [] @@ -31,6 +41,52 @@ "command": "make clean", "type": "shell", "problemMatcher": [] + }, + { + "label": "[wsl] build", + "group": { + "kind": "build", + "isDefault": true + }, + "type": "process", + "command": "bash", + "args": [ + "-c", "make build" + ] + }, + { + "label": "[wsl] clean", + "group": { + "kind": "build", + "isDefault": false + }, + "type": "process", + "command": "bash", + "args": [ + "-c", "make clean" + ] + }, + { + "label": "[win32] build", + "group": { + "kind": "build", + "isDefault": true + }, + "command": "make PLATFORM=windows build", + "type": "shell", + "problemMatcher": [ + "$msCompile" + ] + }, + { + "label": "[win32] clean", + "group": { + "kind": "build", + "isDefault": false + }, + "command": "make PLATFORM=windows clean", + "type": "shell", + "problemMatcher": [] } ] } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 3a8ceab6..4b5321e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,7 @@ RUN apt-get update \ RUN mkdir -p /teddycloud/certs \ && mkdir /teddycloud/config \ && mkdir -p /teddycloud/data/content/default \ + && mkdir -p /teddycloud/data/library \ && mkdir -p /teddycloud/data/www COPY --from=buildenv \ @@ -30,12 +31,11 @@ COPY --from=buildenv \ COPY --from=buildenv \ /buildenv/install/pre/teddycloud /usr/local/bin/teddycloud -VOLUME [ \ - "/teddycloud/data/content", \ - "/teddycloud/data/library", \ - "/teddycloud/certs", \ - "/teddycloud/config", \ - ] +VOLUME \ + "/teddycloud/data/content" \ + "/teddycloud/data/library" \ + "/teddycloud/certs" \ + "/teddycloud/config" COPY docker/docker-entrypoint.sh /usr/local/bin/ RUN chmod +rx /usr/local/bin/docker-entrypoint.sh diff --git a/Makefile b/Makefile index bc1f3860..e53cdac4 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,16 @@ LINK_LO_FILE = $(EXECUTABLE).lo PLATFORM ?= linux ifeq ($(OS),Windows_NT) + SHELL_ENV ?= cmd +# build_arch:="$(shell powershell -NoProfile -Command "$$Env:PROCESSOR_ARCHITECTURE")" +# TODO + build_arch:="AMD64-tbd" +else + SHELL_ENV ?= bash + build_arch:="$(shell arch)" +endif + +ifeq ($(SHELL_ENV),cmd) build_rawDateTime:="${shell date /t} ${shell time /t}" else build_rawDateTime:="${shell date "+%Y-%m-%d %H:%M:%S %z"}" @@ -26,8 +36,11 @@ build_gitDateTime:="${shell git log -1 --format=%ai}" build_gitShortSha:=${shell git rev-parse --short HEAD} build_gitSha:=${shell git rev-parse HEAD} build_gitTag:=${shell git name-rev --tags --name-only $(build_gitSha)} +build_platform:=$(PLATFORM) +build_os:="$(OS)" CFLAGS_VERSION:=-DBUILD_GIT_IS_DIRTY=${build_gitDirty} -DBUILD_GIT_DATETIME=\"${build_gitDateTime}\" -DBUILD_RAW_DATETIME=\"${build_rawDateTime}\" -DBUILD_GIT_SHORT_SHA=\"${build_gitShortSha}\" -DBUILD_GIT_SHA=\"${build_gitSha}\" -DBUILD_GIT_TAG=\"${build_gitTag}\" +CFLAGS_VERSION+=-DBUILD_PLATFORM=\"${build_platform}\" -DBUILD_OS=\"${build_os}\" -DBUILD_ARCH=\"${build_arch}\" build_gitTagPrefix:=$(firstword $(subst _, ,$(build_gitTag))) ifeq ($(build_gitTagPrefix),tc) @@ -87,9 +100,9 @@ ifeq ($(PLATFORM),windows) endif CC = cl.exe LD = link.exe - LFLAGS += /LIBPATH:"$(WindowsSdkDir)\lib\$(WindowsSDKLibVersion)\um\$(VSCMD_ARG_TGT_ARCH)" - LFLAGS += /LIBPATH:"$(WindowsSdkDir)\lib\$(WindowsSDKLibVersion)\ucrt\$(VSCMD_ARG_TGT_ARCH)" - LFLAGS += /LIBPATH:"$(VCToolsInstallDir)\lib\$(VSCMD_ARG_TGT_ARCH)" + LFLAGS += /LIBPATH:"$(WindowsSdkDir)lib\$(WindowsSDKLibVersion)\um\$(VSCMD_ARG_TGT_ARCH)" + LFLAGS += /LIBPATH:"$(WindowsSdkDir)lib\$(WindowsSDKLibVersion)\ucrt\$(VSCMD_ARG_TGT_ARCH)" + LFLAGS += /LIBPATH:"$(VCToolsInstallDir)lib\$(VSCMD_ARG_TGT_ARCH)" endif ## posix/linux specific headers/sources @@ -172,6 +185,9 @@ CYCLONE_SOURCES = \ cyclone/cyclone_tcp/http/http_common.c \ cyclone/cyclone_tcp/http/http_server.c \ cyclone/cyclone_tcp/http/http_server_misc.c \ + cyclone/cyclone_tcp/mqtt/mqtt_client.c \ + cyclone/cyclone_tcp/mqtt/mqtt_client_packet.c \ + cyclone/cyclone_tcp/mqtt/mqtt_client_misc.c \ cyclone/cyclone_ssl/tls.c \ cyclone/cyclone_ssl/tls_cipher_suites.c \ cyclone/cyclone_ssl/tls_handshake.c \ @@ -245,6 +261,7 @@ CYCLONE_SOURCES := $(filter-out \ cyclone/cyclone_tcp/http/http_server.c \ cyclone/cyclone_tcp/http/http_server_misc.c \ cyclone/cyclone_ssl/tls_certificate.c \ + cyclone/cyclone_tcp/mqtt/mqtt_client_transport.c \ , $(CYCLONE_SOURCES)) # and add modified ones @@ -252,6 +269,7 @@ CYCLONE_SOURCES += \ src/cyclone/common/debug.c \ src/cyclone/cyclone_tcp/http/http_server.c \ src/cyclone/cyclone_tcp/http/http_server_misc.c \ + src/cyclone/cyclone_tcp/mqtt/mqtt_client_transport.c \ src/cyclone/cyclone_ssl/tls_certificate.c CFLAGS += -D GPL_LICENSE_TERMS_ACCEPTED diff --git a/README.md b/README.md index f217d154..fbdaa381 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Currently implemented are: ## Preparation ### Generate certificates -First of all you'll need to generate the CA and certificates with the starting date 2015-11-03: ```faketime '2015-11-03 00:00:00' gencerts.sh``` Those will be placed in ```/certs/server/```. +First of all you'll need to generate the CA and certificates with the starting date 2015-11-03: ```./gencerts.sh``` Those will be placed in ```/certs/server/```. This also generates the replacement CA for the toniebox ```certs/server/ca.der```. If you are using docker, this will happen automatically. @@ -36,11 +36,14 @@ You'll need the ```flash:/cert/ca.der``` (Boxine CA), ```flash:/cert/client.der` #### CC3200 You can use the [cc3200tool](https://github.com/toniebox-reverse-engineering/cc3200tool) to dump your certificates over the Tag Connect debug port of the box. If you have installed the HackieboxNG Bootloader you should already have those files in your backup. ``` -python cc.py -p COM3 read_file /cert/ca.der cert/ca.der read_file /cert/private.der cert/private.der read_file /cert/client.der cert/client.der +cc3200tool -p COM3 read_file /cert/ca.der cert/ca.der read_file /cert/private.der cert/private.der read_file /cert/client.der cert/client.der ``` #### CC3235 -You'll have to manually extract it from the flash of the box with a SOP8 clamp directly from the memory or by desoldering it. Reading in-circuit can be tricky, but is possible. - +You'll have to manually extract it from the flash of the box with a SOP8 clamp directly from the memory or by desoldering it. Reading in-circuit can be tricky, but is possible. I recommend flashrom as tool for that. It may be necessary to use a more recent version of it. +You can use the [cc3200tool](https://github.com/toniebox-reverse-engineering/cc3200tool) to extract your certificates from the flash dump. +``` +cc3200tool -if cc32xx-flash.bin -d cc32xx read_all_files extract/ +``` #### ESP32 You can extract the flash memory via the debug port of the box and the esptool. Keep your backup! Please connect the jumper J100 (Boot) and reset the box to put it into the required mode. Connect your 3.3V UART to J103 (TxD, RxD, GND). @@ -59,13 +62,15 @@ cp certs/server/ca.der certs/client/esp32-fakeca/CA.DER #### CC3200 It is recommended to flash the replacement CA to /cert/c2.der and use the hackiebox-ng bootloader with the altCA patch. This will allow you to switch between the original and your replacement certificate. If you have installed the HackieboxNG Bootloader and the Hackiebox CFW you may upload the certificate via the webinterface of the CFW. ``` -python cc.py -p COM3 write_file certs/server/ca.der /cert/c2.der +cc3200tool -p COM3 write_file certs/server/ca.der /cert/c2.der ``` -**Beware** The ```blockCheckRemove.310``` and the ```noHide.308``` patch breaks the content passthrough to Boxine. If you are using firmware 3.1.0_BF4 isn't compatible with many patches, except the alt* ones. Please disable them. +**Beware** The ```blockCheckRemove.310```, ```noCerts.305``` and the ```noHide.308``` patch breaks the content passthrough to Boxine. If you are using firmware 3.1.0_BF4 isn't compatible with many patches, except the alt* ones. Please disable them by removing them in the [```ngCfg.json```](https://github.com/toniebox-reverse-engineering/hackiebox_cfw_ng/wiki/Bootloader#configuration) on the SD card. #### CC3235 -Replace the original CA within your flash dump with the replacement CA and reflash it to your box. -(no manual or tool available yet) +Replace the original CA within your flash dump with the replacement CA and reflash it to your box. I recommend flashrom for that +``` +cc3200tool -if cc32xx-flash.bin -of cc32xx-flash.customca.bin -d cc32xx customca.der /cert/ca.der +``` #### ESP32 Replace the original CA within your flash dump with esptool. @@ -86,7 +91,23 @@ Set the DNS entries for ```prod.de.tbs.toys``` and ```rtnl.bxcl.de``` to the Ted ### Content Please put your content into the ```/data/content/default/``` in the same structure as on your toniebox. You can place an empty ```500304E0.live``` file beside the content files to mark them as live. With ```500304E0.nocloud``` you can prevent the usage of the Boxine cloud for that tag. +### Webinterface +Currently the interface to teddycloud is reachable through the IP of the docker container at port 80 or 443 (depending on your ```docker-compose.yaml```). Changes affecting the toniebox (volume, LED) which are made through this interface will only be reflected onto the toniebox after pressing the big ear for a few seconds until a beep occurs. + +As an additional frontend is still being developed, you can reach a second frontend at ```xxx.xxx.xxx/web```. Changes made here are instantly live on the box. + ## Docker hints The docker container automatically generates the server certificates on first run. You can extract the ```certs/server/ca.der``` for your box after that. The container won't run without the ```flash:/cert/ca.der``` (Boxine CA), ```flash:/cert/client.der``` (Client Cert) and ```flash:/cert/private.der``` (Client private key). An example [docker-compose.yaml can be found within the docker subdir.](docker/docker-compose.yaml) + + +## Attribution + +The icons used are from here: +* img_empty.png: https://www.flaticon.com/free-icon/ask_1372671 +* img_unknown.png: https://www.flaticon.com/free-icon/ask_1923795 +* img_custom.png/favicon.ico: https://www.flaticon.com/free-icon/dog_2829818 + +Thanks for the original authors for these great icons. + diff --git a/contrib/data/www/img_custom.png b/contrib/data/www/img_custom.png new file mode 100644 index 00000000..33f1af5c Binary files /dev/null and b/contrib/data/www/img_custom.png differ diff --git a/contrib/data/www/img_empty.png b/contrib/data/www/img_empty.png new file mode 100644 index 00000000..ea0ece0a Binary files /dev/null and b/contrib/data/www/img_empty.png differ diff --git a/contrib/data/www/index.html b/contrib/data/www/index.html index 9d1e844f..e09eb0c7 100644 --- a/contrib/data/www/index.html +++ b/contrib/data/www/index.html @@ -1194,6 +1194,7 @@

File Viewer

this.handleModeChange = this.handleModeChange.bind(this); this.hexToStr = this.hexToStr.bind(this); this.littleEndianToNum = this.littleEndianToNum.bind(this); + this.messagesEnd = React.createRef(); } componentDidMount() { @@ -1208,6 +1209,15 @@

File Viewer

this.deinitSSE(); } } + if (this.state.enabled && this.state.messages !== prevState.messages) { + this.messagesEnd.current.scrollIntoView({ behavior: 'smooth' }); + } + } + + appendMessage = (text) => { + this.setState(prevState => ({ + messages: [...prevState.messages, text] + })); } hexToStr(hex) { @@ -1242,11 +1252,8 @@

File Viewer

initSSE = () => { const eventSource = new EventSource('/api/sse'); - eventSource.onopen = e => { - console.log("Connection to server opened", e); - }; - eventSource.addEventListener('keep-alive', e => { + /* maybe later we have the box's ID from the certificate so we could show online states */ console.log("keep-alive event received:", e); }); @@ -1258,7 +1265,6 @@

File Viewer

})); }); - eventSource.addEventListener('rtnl-raw-log2', e => { const data = JSON.parse(e.data); const functionHandlers = { @@ -1266,10 +1272,7 @@

File Viewer

"15-15452": (payload) => { if (payload.length === 16) { const rearrangedPayload = payload.slice(8) + payload.slice(0, 8); - this.setState(prevState => ({ - messages: [...prevState.messages, - `UnknownTag | ${rearrangedPayload}`] - })); + this.appendMessage(`UnknownTag | ${rearrangedPayload}`); } else { console.log(`Incorrect payload length for '${payload}'. Unable to rearrange.`); } @@ -1277,10 +1280,7 @@

File Viewer

"15-16065": (payload) => { if (payload.length === 16) { const rearrangedPayload = payload.slice(8) + payload.slice(0, 8); - this.setState(prevState => ({ - messages: [...prevState.messages, - `KnownTag | ${rearrangedPayload}`] - })); + this.appendMessage(`KnownTag | ${rearrangedPayload}`); } else { console.log(`Incorrect payload length for '${payload}'. Unable to rearrange.`); } @@ -1288,10 +1288,7 @@

File Viewer

"12-15427": (payload) => { if (payload.length === 8) { const value = this.littleEndianToNum(payload); - this.setState(prevState => ({ - messages: [...prevState.messages, - `UpsideState | ${value}`] - })); + this.appendMessage(`UpsideState | ${value}`); } else { console.log(`Incorrect payload length for '${payload}'. Unable to rearrange.`); } @@ -1299,29 +1296,22 @@

File Viewer

"12-15426": (payload) => { if (payload.length === 8) { const value = this.littleEndianToNum(payload); - this.setState(prevState => ({ - messages: [...prevState.messages, - `UprightState | ${value}`] - })); + this.appendMessage(`UprightState | ${value}`); } else { console.log(`Incorrect payload length for '${payload}'. Unable to rearrange.`); } }, }; - - console.log("raw", data); - this.setState(prevState => ({ - messages: [...prevState.messages, + this.appendMessage( "Raw2 |" + " #" + data.data.sequence + " Uptime: " + data.data.uptime + - " Func: " + data.data.function_group + "-" + data.data.function + + " Func: " + data.data.function_group.toString().padStart(2, ' ') + "-" + data.data.function + " Payload: '" + data.data.field6 + "'" + - " ASCII: '" + this.hexToStr(data.data.field6) + "'"] - })); + " ASCII: '" + this.hexToStr(data.data.field6) + "'"); - const funcKey = `${data.data.function_group}-${data.data.function}`; + const funcKey = `${data.data.function_group.toString().padStart(2, ' ')}-${data.data.function}`; if (functionHandlers[funcKey]) { functionHandlers[funcKey](data.data.field6); } @@ -1331,12 +1321,10 @@

File Viewer

const data = JSON.parse(e.data); console.log("raw", data); - this.setState(prevState => ({ - messages: [...prevState.messages, + this.appendMessage( "Raw3 |" + " Datetime: " + data.data.datetime + - " Unknown: " + data.data.field2] - })); + " Unknown: " + data.data.field2); }); eventSource.onerror = e => { @@ -1358,7 +1346,8 @@

File Viewer

handleModeChange = () => { this.setState(prevState => ({ - enabled: !prevState.enabled + enabled: !prevState.enabled, + messages: [] })); }; @@ -1383,6 +1372,7 @@

RTNL-Log

{message} ))} +
)} diff --git a/contrib/data/www/web/asset-manifest.json b/contrib/data/www/web/asset-manifest.json index 72ed1f99..c3b68fee 100644 --- a/contrib/data/www/web/asset-manifest.json +++ b/contrib/data/www/web/asset-manifest.json @@ -1,15 +1,15 @@ { "files": { "main.css": "/web/static/css/main.e6c13ad2.css", - "main.js": "/web/static/js/main.01d9f9c0.js", + "main.js": "/web/static/js/main.3c1d6764.js", "static/media/logo.png": "/web/static/media/logo.2f09160138082fd1c6f8.png", "index.html": "/web/index.html", "static/media/getFetch.cjs": "/web/static/media/getFetch.40f37ddea2378391108f.cjs", "main.e6c13ad2.css.map": "/web/static/css/main.e6c13ad2.css.map", - "main.01d9f9c0.js.map": "/web/static/js/main.01d9f9c0.js.map" + "main.3c1d6764.js.map": "/web/static/js/main.3c1d6764.js.map" }, "entrypoints": [ "static/css/main.e6c13ad2.css", - "static/js/main.01d9f9c0.js" + "static/js/main.3c1d6764.js" ] } \ No newline at end of file diff --git a/contrib/data/www/web/index.html b/contrib/data/www/web/index.html index 6dfe7715..13230602 100644 --- a/contrib/data/www/web/index.html +++ b/contrib/data/www/web/index.html @@ -1 +1 @@ -TeddyCloud
\ No newline at end of file +TeddyCloud
\ No newline at end of file diff --git a/contrib/data/www/web/static/js/main.01d9f9c0.js b/contrib/data/www/web/static/js/main.01d9f9c0.js deleted file mode 100644 index 9fac32fe..00000000 --- a/contrib/data/www/web/static/js/main.01d9f9c0.js +++ /dev/null @@ -1,3 +0,0 @@ -/*! For license information please see main.01d9f9c0.js.LICENSE.txt */ -!function(){var e={694:function(e,t){var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t=t?e:""+Array(t+1-r.length).join(n)+e},b={s:m,z:function(e){var t=-e.utcOffset(),n=Math.abs(t),r=Math.floor(n/60),o=n%60;return(t<=0?"+":"-")+m(r,2,"0")+":"+m(o,2,"0")},m:function e(t,n){if(t.date()1)return e(i[0])}else{var c=t.name;w[c]=t,o=c}return!r&&o&&(y=o),o||!r&&y},C=function(e,t){if(x(e))return e.clone();var n="object"==typeof t?t:{};return n.date=e,n.args=arguments,new E(n)},k=b;k.l=S,k.i=x,k.w=function(e,t){return C(e,{locale:t.$L,utc:t.$u,x:t.$x,$offset:t.$offset})};var E=function(){function g(e){this.$L=S(e.locale,null,!0),this.parse(e)}var m=g.prototype;return m.parse=function(e){this.$d=function(e){var t=e.date,n=e.utc;if(null===t)return new Date(NaN);if(k.u(t))return new Date;if(t instanceof Date)return new Date(t);if("string"==typeof t&&!/Z$/i.test(t)){var r=t.match(h);if(r){var o=r[2]-1||0,a=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],o,r[3]||1,r[4]||0,r[5]||0,r[6]||0,a)):new Date(r[1],o,r[3]||1,r[4]||0,r[5]||0,r[6]||0,a)}}return new Date(t)}(e),this.$x=e.x||{},this.init()},m.init=function(){var e=this.$d;this.$y=e.getFullYear(),this.$M=e.getMonth(),this.$D=e.getDate(),this.$W=e.getDay(),this.$H=e.getHours(),this.$m=e.getMinutes(),this.$s=e.getSeconds(),this.$ms=e.getMilliseconds()},m.$utils=function(){return k},m.isValid=function(){return!(this.$d.toString()===p)},m.isSame=function(e,t){var n=C(e);return this.startOf(t)<=n&&n<=this.endOf(t)},m.isAfter=function(e,t){return C(e)68?1900:2e3)},c=function(e){return function(t){this[e]=+t}},l=[/[+-]\d\d:?(\d\d)?|Z/,function(e){(this.zone||(this.zone={})).offset=function(e){if(!e)return 0;if("Z"===e)return 0;var t=e.match(/([+-]|\d\d)/g),n=60*t[1]+(+t[2]||0);return 0===n?0:"+"===t[0]?-n:n}(e)}],s=function(e){var t=a[e];return t&&(t.indexOf?t:t.s.concat(t.f))},u=function(e,t){var n,r=a.meridiem;if(r){for(var o=1;o<=24;o+=1)if(e.indexOf(r(o,0,t))>-1){n=o>12;break}}else n=e===(t?"pm":"PM");return n},d={A:[o,function(e){this.afternoon=u(e,!1)}],a:[o,function(e){this.afternoon=u(e,!0)}],S:[/\d/,function(e){this.milliseconds=100*+e}],SS:[n,function(e){this.milliseconds=10*+e}],SSS:[/\d{3}/,function(e){this.milliseconds=+e}],s:[r,c("seconds")],ss:[r,c("seconds")],m:[r,c("minutes")],mm:[r,c("minutes")],H:[r,c("hours")],h:[r,c("hours")],HH:[r,c("hours")],hh:[r,c("hours")],D:[r,c("day")],DD:[n,c("day")],Do:[o,function(e){var t=a.ordinal,n=e.match(/\d+/);if(this.day=n[0],t)for(var r=1;r<=31;r+=1)t(r).replace(/\[|\]/g,"")===e&&(this.day=r)}],M:[r,c("month")],MM:[n,c("month")],MMM:[o,function(e){var t=s("months"),n=(s("monthsShort")||t.map((function(e){return e.slice(0,3)}))).indexOf(e)+1;if(n<1)throw new Error;this.month=n%12||n}],MMMM:[o,function(e){var t=s("months").indexOf(e)+1;if(t<1)throw new Error;this.month=t%12||t}],Y:[/[+-]?\d+/,c("year")],YY:[n,function(e){this.year=i(e)}],YYYY:[/\d{4}/,c("year")],Z:l,ZZ:l};function f(n){var r,o;r=n,o=a&&a.formats;for(var i=(n=r.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(t,n,r){var a=r&&r.toUpperCase();return n||o[r]||e[r]||o[a].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,n){return t||n.slice(1)}))}))).match(t),c=i.length,l=0;l-1)return new Date(("X"===t?1e3:1)*e);var r=f(t)(e),o=r.year,a=r.month,i=r.day,c=r.hours,l=r.minutes,s=r.seconds,u=r.milliseconds,d=r.zone,p=new Date,h=i||(o||a?1:p.getDate()),v=o||p.getFullYear(),g=0;o&&!a||(g=a>0?a-1:p.getMonth());var m=c||0,b=l||0,y=s||0,w=u||0;return d?new Date(Date.UTC(v,g,h,m,b,y,w+60*d.offset*1e3)):n?new Date(Date.UTC(v,g,h,m,b,y,w)):new Date(v,g,h,m,b,y,w)}catch(e){return new Date("")}}(t,c,r),this.init(),d&&!0!==d&&(this.$L=this.locale(d).$L),u&&t!=this.format(c)&&(this.$d=new Date("")),a={}}else if(c instanceof Array)for(var p=c.length,h=1;h<=p;h+=1){i[1]=c[h-1];var v=n.apply(this,i);if(v.isValid()){this.$d=v.$d,this.$L=v.$L,this.init();break}h===p&&(this.$d=new Date(""))}else o.call(this,e)}}}()},36:function(e){e.exports=function(){"use strict";return function(e,t,n){var r=t.prototype,o=function(e){return e&&(e.indexOf?e:e.s)},a=function(e,t,n,r,a){var i=e.name?e:e.$locale(),c=o(i[t]),l=o(i[n]),s=c||l.map((function(e){return e.slice(0,r)}));if(!a)return s;var u=i.weekStart;return s.map((function(e,t){return s[(t+(u||0))%7]}))},i=function(){return n.Ls[n.locale()]},c=function(e,t){return e.formats[t]||function(e){return e.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,n){return t||n.slice(1)}))}(e.formats[t.toUpperCase()])},l=function(){var e=this;return{months:function(t){return t?t.format("MMMM"):a(e,"months")},monthsShort:function(t){return t?t.format("MMM"):a(e,"monthsShort","months",3)},firstDayOfWeek:function(){return e.$locale().weekStart||0},weekdays:function(t){return t?t.format("dddd"):a(e,"weekdays")},weekdaysMin:function(t){return t?t.format("dd"):a(e,"weekdaysMin","weekdays",2)},weekdaysShort:function(t){return t?t.format("ddd"):a(e,"weekdaysShort","weekdays",3)},longDateFormat:function(t){return c(e.$locale(),t)},meridiem:this.$locale().meridiem,ordinal:this.$locale().ordinal}};r.localeData=function(){return l.bind(this)()},n.localeData=function(){var e=i();return{firstDayOfWeek:function(){return e.weekStart||0},weekdays:function(){return n.weekdays()},weekdaysShort:function(){return n.weekdaysShort()},weekdaysMin:function(){return n.weekdaysMin()},months:function(){return n.months()},monthsShort:function(){return n.monthsShort()},longDateFormat:function(t){return c(e,t)},meridiem:e.meridiem,ordinal:e.ordinal}},n.months=function(){return a(i(),"months")},n.monthsShort=function(){return a(i(),"monthsShort","months",3)},n.weekdays=function(e){return a(i(),"weekdays",null,null,e)},n.weekdaysShort=function(e){return a(i(),"weekdaysShort","weekdays",3,e)},n.weekdaysMin=function(e){return a(i(),"weekdaysMin","weekdays",2,e)}}}()},216:function(e){e.exports=function(){"use strict";var e="week",t="year";return function(n,r,o){var a=r.prototype;a.week=function(n){if(void 0===n&&(n=null),null!==n)return this.add(7*(n-this.week()),"day");var r=this.$locale().yearStart||1;if(11===this.month()&&this.date()>25){var a=o(this).startOf(t).add(1,t).date(r),i=o(this).endOf(e);if(a.isBefore(i))return 1}var c=o(this).startOf(t).date(r).startOf(e).subtract(1,"millisecond"),l=this.diff(c,e,!0);return l<0?o(this).startOf("week").week():Math.ceil(l)},a.weeks=function(e){return void 0===e&&(e=null),this.week(e)}}}()},834:function(e){e.exports=function(){"use strict";return function(e,t){t.prototype.weekYear=function(){var e=this.month(),t=this.week(),n=this.year();return 1===t&&11===e?n+1:0===e&&t>=52?n-1:n}}}()},334:function(e){e.exports=function(){"use strict";return function(e,t){t.prototype.weekday=function(e){var t=this.$locale().weekStart||0,n=this.$W,r=(n