Compare commits

..

No commits in common. "main" and "v0.0.23" have entirely different histories.

68 changed files with 1038 additions and 1504 deletions

View File

@ -14,7 +14,7 @@ IndentWidth: 4
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
ObjCBlockIndentWidth: 4 ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: false ObjCBreakBeforeNestedBlockParam: false
SortIncludes: true SortIncludes: false
TabWidth: 4 TabWidth: 4
UseTab: Always UseTab: Always
... ...

View File

@ -24,7 +24,7 @@ jobs:
uses: android-actions/setup-android@v3 uses: android-actions/setup-android@v3
with: with:
packages: 'tools platform-tools build-tools;34.0.0 platforms;android-34 ndk;26.3.11579264' packages: 'tools platform-tools build-tools;34.0.0 platforms;android-34 ndk;26.3.11579264'
- run: sudo apt update && sudo apt install -y doxygen graphviz mingw-w64 libgpgme11 - run: sudo apt update && sudo apt install -y doxygen graphviz mingw-w64
- run: ANDROID_SDK=$HOME/.android/sdk make -j`nproc` all docs - run: ANDROID_SDK=$HOME/.android/sdk make -j`nproc` all docs
- run: docker build . - run: docker build .
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3

View File

@ -3,14 +3,14 @@
MAKEFLAGS += --warn-undefined-variables MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules MAKEFLAGS += --no-builtin-rules
VERSION_CODE := 28 VERSION_CODE := 27
VERSION_NUMBER := 0.0.24-wip VERSION_NUMBER := 0.0.23
VERSION_NAME := Honey bunches of boats. VERSION_NAME := Me upon my pony on my boat.
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3460100.zip SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3460100.zip
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.17.0/bundletool-all-1.17.0.jar BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.17.0/bundletool-all-1.17.0.jar
APPIMAGETOOL_URL := https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage LINUXDEPLOY_URL := https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20240109-1/linuxdeploy-x86_64.AppImage
APPIMAGETOOL_MD5 := e989fadfc4d685fd3d6aeeb9b525d74d out/appimagetool LINUXDEPLOY_MD5 := 659d69326199524552bfbbe46cb0adae out/linuxdeploy
PROJECT = tildefriends PROJECT = tildefriends
BUILD_DIR ?= out BUILD_DIR ?= out
@ -103,6 +103,9 @@ BUILD_TYPES += \
androidrelease-x86_64 androidrelease-x86_64
all: out/TildeFriends-arm-debug.apk out/TildeFriends-arm-release.apk out/TildeFriends-x86-debug.apk out/TildeFriends-x86-release.apk out/TildeFriends-release.fdroid.apk all: out/TildeFriends-arm-debug.apk out/TildeFriends-arm-release.apk out/TildeFriends-x86-debug.apk out/TildeFriends-x86-release.apk out/TildeFriends-release.fdroid.apk
endif endif
ifeq ($(UNAME_S),Linux)
all: appimage
endif
WINDOWS_TARGETS := \ WINDOWS_TARGETS := \
out/windebug/tildefriends.exe \ out/windebug/tildefriends.exe \
@ -162,9 +165,7 @@ NONANDROID_RELEASE_TARGETS := $(filter-out $(ANDROID_ARM64_TARGETS),$(RELEASE_TA
NONANDROID_TARGETS := $(filter-out $(ANDROID_TARGETS),$(ALL_TARGETS)) NONANDROID_TARGETS := $(filter-out $(ANDROID_TARGETS),$(ALL_TARGETS))
NONMACOS_TARGETS := $(filter-out $(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS),$(ALL_TARGETS)) NONMACOS_TARGETS := $(filter-out $(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS),$(ALL_TARGETS))
DEADSTRIP_TARGETS := $(filter-out $(ANDROID_TARGETS),$(NONMACOS_TARGETS)) DEADSTRIP_TARGETS := $(filter-out $(ANDROID_TARGETS),$(NONMACOS_TARGETS))
ifneq ($(UNAME_S),OpenBSD)
$(NONMACOS_TARGETS): LDFLAGS += -static-libgcc $(NONMACOS_TARGETS): LDFLAGS += -static-libgcc
endif
$(NONANDROID_TARGETS): CFLAGS += -fno-omit-frame-pointer $(NONANDROID_TARGETS): CFLAGS += -fno-omit-frame-pointer
$(filter-out $(WINDOWS_TARGETS),$(ALL_TARGETS)): LDFLAGS += -rdynamic $(filter-out $(WINDOWS_TARGETS),$(ALL_TARGETS)): LDFLAGS += -rdynamic
@ -230,9 +231,6 @@ $(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/inc
$(IOSSIM_TARGETS): LDFLAGS += -Ldeps/openssl/ios/iossimulator-xcrun/usr/local/lib $(IOSSIM_TARGETS): LDFLAGS += -Ldeps/openssl/ios/iossimulator-xcrun/usr/local/lib
ifeq ($(UNAME_M),x86_64) ifeq ($(UNAME_M),x86_64)
ifeq ($(UNAME_S),Linux)
all: appimage
endif
ifneq ($(UNAME_S),Haiku) ifneq ($(UNAME_S),Haiku)
out/debug/tildefriends: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common out/debug/tildefriends: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
out/debug/tildefriends: LDFLAGS += -fsanitize=address -fsanitize=undefined out/debug/tildefriends: LDFLAGS += -fsanitize=address -fsanitize=undefined
@ -280,101 +278,98 @@ $(filter-out $(BUILD_DIR)/android% $(BUILD_DIR)/macos% $(BUILD_DIR)/ios%,$(APP_O
endif endif
ARES_SOURCES := \ ARES_SOURCES := \
deps/c-ares/src/lib/ares_addrinfo2hostent.c \ deps/c-ares/src/lib/ares_platform.c \
deps/c-ares/src/lib/ares_addrinfo_localhost.c \ deps/c-ares/src/lib/record/ares_dns_mapping.c \
deps/c-ares/src/lib/ares_android.c \ deps/c-ares/src/lib/record/ares_dns_parse.c \
deps/c-ares/src/lib/ares_cancel.c \ deps/c-ares/src/lib/record/ares_dns_write.c \
deps/c-ares/src/lib/ares_close_sockets.c \ deps/c-ares/src/lib/record/ares_dns_name.c \
deps/c-ares/src/lib/ares_conn.c \ deps/c-ares/src/lib/record/ares_dns_record.c \
deps/c-ares/src/lib/ares_cookie.c \ deps/c-ares/src/lib/record/ares_dns_multistring.c \
deps/c-ares/src/lib/ares_data.c \
deps/c-ares/src/lib/ares_destroy.c \ deps/c-ares/src/lib/ares_destroy.c \
deps/c-ares/src/lib/ares_free_hostent.c \ deps/c-ares/src/lib/ares_data.c \
deps/c-ares/src/lib/ares_free_string.c \
deps/c-ares/src/lib/ares_freeaddrinfo.c \
deps/c-ares/src/lib/ares_getaddrinfo.c \
deps/c-ares/src/lib/ares_getenv.c \
deps/c-ares/src/lib/ares_gethostbyaddr.c \
deps/c-ares/src/lib/ares_gethostbyname.c \
deps/c-ares/src/lib/ares_getnameinfo.c \
deps/c-ares/src/lib/ares_hosts_file.c \
deps/c-ares/src/lib/ares_init.c \
deps/c-ares/src/lib/ares_library_init.c \
deps/c-ares/src/lib/ares_metrics.c \
deps/c-ares/src/lib/ares_options.c \
deps/c-ares/src/lib/ares_parse_into_addrinfo.c \
deps/c-ares/src/lib/ares_process.c \
deps/c-ares/src/lib/ares_qcache.c \
deps/c-ares/src/lib/ares_query.c \
deps/c-ares/src/lib/ares_search.c \
deps/c-ares/src/lib/ares_send.c \
deps/c-ares/src/lib/ares_set_socket_functions.c \
deps/c-ares/src/lib/ares_socket.c \
deps/c-ares/src/lib/ares_sortaddrinfo.c \
deps/c-ares/src/lib/ares_strerror.c \
deps/c-ares/src/lib/ares_sysconfig.c \ deps/c-ares/src/lib/ares_sysconfig.c \
deps/c-ares/src/lib/ares_sysconfig_files.c \ deps/c-ares/src/lib/ares_cancel.c \
deps/c-ares/src/lib/ares_sysconfig_mac.c \ deps/c-ares/src/lib/ares_metrics.c \
deps/c-ares/src/lib/ares_sysconfig_win.c \ deps/c-ares/src/lib/ares_getnameinfo.c \
deps/c-ares/src/lib/ares_update_servers.c \ deps/c-ares/src/lib/legacy/ares_parse_txt_reply.c \
deps/c-ares/src/lib/ares_version.c \ deps/c-ares/src/lib/legacy/ares_parse_naptr_reply.c \
deps/c-ares/src/lib/dsa/ares_array.c \
deps/c-ares/src/lib/dsa/ares_htable.c \
deps/c-ares/src/lib/dsa/ares_htable_asvp.c \
deps/c-ares/src/lib/dsa/ares_htable_dict.c \
deps/c-ares/src/lib/dsa/ares_htable_strvp.c \
deps/c-ares/src/lib/dsa/ares_htable_szvp.c \
deps/c-ares/src/lib/dsa/ares_htable_vpvp.c \
deps/c-ares/src/lib/dsa/ares_llist.c \
deps/c-ares/src/lib/dsa/ares_slist.c \
deps/c-ares/src/lib/event/ares_event_configchg.c \
deps/c-ares/src/lib/event/ares_event_epoll.c \
deps/c-ares/src/lib/event/ares_event_kqueue.c \
deps/c-ares/src/lib/event/ares_event_poll.c \
deps/c-ares/src/lib/event/ares_event_select.c \
deps/c-ares/src/lib/event/ares_event_thread.c \
deps/c-ares/src/lib/event/ares_event_wake_pipe.c \
deps/c-ares/src/lib/event/ares_event_win32.c \
deps/c-ares/src/lib/inet_net_pton.c \
deps/c-ares/src/lib/inet_ntop.c \
deps/c-ares/src/lib/legacy/ares_create_query.c \ deps/c-ares/src/lib/legacy/ares_create_query.c \
deps/c-ares/src/lib/legacy/ares_parse_mx_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_srv_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_ptr_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_caa_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c \
deps/c-ares/src/lib/legacy/ares_expand_name.c \ deps/c-ares/src/lib/legacy/ares_expand_name.c \
deps/c-ares/src/lib/legacy/ares_parse_uri_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_a_reply.c \
deps/c-ares/src/lib/legacy/ares_expand_string.c \ deps/c-ares/src/lib/legacy/ares_expand_string.c \
deps/c-ares/src/lib/legacy/ares_fds.c \ deps/c-ares/src/lib/legacy/ares_fds.c \
deps/c-ares/src/lib/legacy/ares_getsock.c \
deps/c-ares/src/lib/legacy/ares_parse_a_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_caa_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_mx_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_naptr_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_ns_reply.c \ deps/c-ares/src/lib/legacy/ares_parse_ns_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_ptr_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_soa_reply.c \ deps/c-ares/src/lib/legacy/ares_parse_soa_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_srv_reply.c \ deps/c-ares/src/lib/legacy/ares_getsock.c \
deps/c-ares/src/lib/legacy/ares_parse_txt_reply.c \ deps/c-ares/src/lib/windows_port.c \
deps/c-ares/src/lib/legacy/ares_parse_uri_reply.c \ deps/c-ares/src/lib/ares_qcache.c \
deps/c-ares/src/lib/record/ares_dns_mapping.c \ deps/c-ares/src/lib/ares_update_servers.c \
deps/c-ares/src/lib/record/ares_dns_multistring.c \ deps/c-ares/src/lib/ares_process.c \
deps/c-ares/src/lib/record/ares_dns_name.c \ deps/c-ares/src/lib/ares_getenv.c \
deps/c-ares/src/lib/record/ares_dns_parse.c \ deps/c-ares/src/lib/ares_gethostbyname.c \
deps/c-ares/src/lib/record/ares_dns_record.c \ deps/c-ares/src/lib/ares_send.c \
deps/c-ares/src/lib/record/ares_dns_write.c \ deps/c-ares/src/lib/dsa/ares__slist.c \
deps/c-ares/src/lib/str/ares_buf.c \ deps/c-ares/src/lib/dsa/ares__htable.c \
deps/c-ares/src/lib/str/ares_str.c \ deps/c-ares/src/lib/dsa/ares__llist.c \
deps/c-ares/src/lib/dsa/ares__htable_szvp.c \
deps/c-ares/src/lib/dsa/ares__htable_asvp.c \
deps/c-ares/src/lib/dsa/ares__htable_vpvp.c \
deps/c-ares/src/lib/dsa/ares__htable_strvp.c \
deps/c-ares/src/lib/dsa/ares__array.c \
deps/c-ares/src/lib/ares__socket.c \
deps/c-ares/src/lib/event/ares_event_poll.c \
deps/c-ares/src/lib/event/ares_event_thread.c \
deps/c-ares/src/lib/event/ares_event_select.c \
deps/c-ares/src/lib/event/ares_event_kqueue.c \
deps/c-ares/src/lib/event/ares_event_configchg.c \
deps/c-ares/src/lib/event/ares_event_epoll.c \
deps/c-ares/src/lib/event/ares_event_wake_pipe.c \
deps/c-ares/src/lib/event/ares_event_win32.c \
deps/c-ares/src/lib/ares_search.c \
deps/c-ares/src/lib/ares__parse_into_addrinfo.c \
deps/c-ares/src/lib/ares__hosts_file.c \
deps/c-ares/src/lib/ares_getaddrinfo.c \
deps/c-ares/src/lib/ares__addrinfo2hostent.c \
deps/c-ares/src/lib/ares_freeaddrinfo.c \
deps/c-ares/src/lib/ares_strerror.c \
deps/c-ares/src/lib/ares_version.c \
deps/c-ares/src/lib/ares_gethostbyaddr.c \
deps/c-ares/src/lib/ares__addrinfo_localhost.c \
deps/c-ares/src/lib/ares_free_hostent.c \
deps/c-ares/src/lib/ares__close_sockets.c \
deps/c-ares/src/lib/ares_free_string.c \
deps/c-ares/src/lib/ares_init.c \
deps/c-ares/src/lib/ares_options.c \
deps/c-ares/src/lib/str/ares_strcasecmp.c \
deps/c-ares/src/lib/str/ares__buf.c \
deps/c-ares/src/lib/str/ares_strsplit.c \ deps/c-ares/src/lib/str/ares_strsplit.c \
deps/c-ares/src/lib/util/ares_iface_ips.c \ deps/c-ares/src/lib/str/ares_str.c \
deps/c-ares/src/lib/ares_sysconfig_mac.c \
deps/c-ares/src/lib/ares__sortaddrinfo.c \
deps/c-ares/src/lib/ares_sysconfig_files.c \
deps/c-ares/src/lib/util/ares__iface_ips.c \
deps/c-ares/src/lib/util/ares__timeval.c \
deps/c-ares/src/lib/util/ares_math.c \ deps/c-ares/src/lib/util/ares_math.c \
deps/c-ares/src/lib/util/ares_rand.c \ deps/c-ares/src/lib/util/ares_rand.c \
deps/c-ares/src/lib/util/ares_threads.c \ deps/c-ares/src/lib/util/ares__threads.c \
deps/c-ares/src/lib/util/ares_timeval.c \ deps/c-ares/src/lib/ares_query.c \
deps/c-ares/src/lib/util/ares_uri.c \ deps/c-ares/src/lib/ares_cookie.c \
deps/c-ares/src/lib/windows_port.c \ deps/c-ares/src/lib/inet_net_pton.c \
deps/c-ares/src/lib/inet_ntop.c \
deps/c-ares/src/lib/ares_library_init.c \
deps/c-ares/src/lib/ares_android.c \
deps/c-ares/src/lib/ares_sysconfig_win.c \
deps/c-ares/src/lib/ares_timeout.c deps/c-ares/src/lib/ares_timeout.c
ARES_OBJS := $(call get_objs,ARES_SOURCES) ARES_OBJS := $(call get_objs,ARES_SOURCES)
$(ARES_OBJS): CFLAGS += \ $(ARES_OBJS): CFLAGS += \
-Ideps/c-ares/include \ -Ideps/c-ares/include \
-Ideps/c-ares/src/lib \ -Ideps/c-ares/src/lib \
-Ideps/c-ares/src/lib/include \
-Ideps/c-ares_config/ \ -Ideps/c-ares_config/ \
-D_GNU_SOURCE \ -D_GNU_SOURCE \
-Wno-unused-function \ -Wno-unused-function \
@ -508,12 +503,10 @@ $(UV_OBJS): CFLAGS += \
-Wno-incompatible-pointer-types \ -Wno-incompatible-pointer-types \
-Wno-maybe-uninitialized \ -Wno-maybe-uninitialized \
-Wno-sign-compare \ -Wno-sign-compare \
-Wno-unknown-attributes \
-Wno-unused-but-set-parameter \ -Wno-unused-but-set-parameter \
-Wno-unused-but-set-variable \ -Wno-unused-but-set-variable \
-Wno-unused-result \ -Wno-unused-result \
-Wno-unused-variable \ -Wno-unused-variable
-Wno-nonnull
$(UV_OBJS): CFLAGS += -fno-lto $(UV_OBJS): CFLAGS += -fno-lto
$(filter out/win%,$(UV_OBJS)): \ $(filter out/win%,$(UV_OBJS)): \
CFLAGS += \ CFLAGS += \
@ -1008,7 +1001,6 @@ out/data.zip: $(RAW_FILES)
out/tildefriends-%.app/tildefriends: out/%/tildefriends out/tildefriends-%.app/Info.plist out/tildefriends-%.app/tildefriends.png out/data.zip out/tildefriends-%.app/tildefriends: out/%/tildefriends out/tildefriends-%.app/Info.plist out/tildefriends-%.app/tildefriends.png out/data.zip
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
@cp -v $< $@ @cp -v $< $@
@cp -v out/data.zip $(@D)/
ifeq ($(HAVE_LINUX_IOS),1) ifeq ($(HAVE_LINUX_IOS),1)
@zsign -q -k .keys/apple.p12 -f -m src/ios/embedded.mobileprovision $(realpath $(dir $@)) @zsign -q -k .keys/apple.p12 -f -m src/ios/embedded.mobileprovision $(realpath $(dir $@))
endif endif
@ -1085,22 +1077,17 @@ endif
out/tildefriends-x86_64.AppImage: out/release/tildefriends out/data.zip out/tildefriends-x86_64.AppImage: out/release/tildefriends out/data.zip
@echo "[appimage] $$@" @echo "[appimage] $$@"
@rm -rf out/tildefriends.AppDir @mkdir -p out/AppDir/usr/bin
@mkdir -p out/tildefriends.AppDir/usr/bin @mkdir -p out/AppDir/usr/share/applications
@mkdir -p out/tildefriends.AppDir/usr/share/applications @mkdir -p out/AppDir/usr/share/icons/hicolor/scalable/apps
@mkdir -p out/tildefriends.AppDir/usr/share/icons/hicolor/scalable/apps @echo $(LINUXDEPLOY_MD5) > out/linuxdeploy.md5
@mkdir -p out/tildefriends.AppDir/usr/share/tildefriends @test -x out/linuxdeploy || curl -q -L -o out/linuxdeploy $(LINUXDEPLOY_URL) && md5sum -c out/linuxdeploy.md5 && chmod +x out/linuxdeploy
@echo $(APPIMAGETOOL_MD5) > out/appimagetool.md5 @echo "[Desktop Entry]\nName=tildefriends\nExec=tildefriends\nIcon=tildefriends\nType=Application\nCategories=Network" > out/AppDir/usr/share/applications/tildefriends.desktop
@test -x out/appimagetool || curl -q -L -o out/appimagetool $(APPIMAGETOOL_URL) && md5sum -c out/appimagetool.md5 && chmod +x out/appimagetool @cp src/ios/tildefriends.svg out/AppDir/usr/share/icons/hicolor/scalable/apps/
@echo "[Desktop Entry]\nName=tildefriends\nExec=/usr/bin/tildefriends\nIcon=/usr/share/icons/hicolor/scalable/apps/tildefriends\nType=Application\nCategories=Network" > out/tildefriends.AppDir/tildefriends.desktop @cat out/release/tildefriends out/data.zip > out/AppDir/usr/bin/tildefriends
@cp src/ios/tildefriends.svg out/tildefriends.AppDir/usr/share/icons/hicolor/scalable/apps/ @chmod +x out/AppDir/usr/bin/tildefriends
@cp src/ios/tildefriends.svg out/tildefriends.AppDir/ @cd out; ./linuxdeploy --appimage-extract; cd ..
@cp out/release/tildefriends out/tildefriends.AppDir/usr/bin/ @unset SOURCE_DATE_EPOCH; cd out; squashfs-root/usr/bin/linuxdeploy --appdir AppDir --output appimage; cd ..
@cp out/data.zip out/tildefriends.AppDir/usr/share/tildefriends/data.zip
@echo "#!/bin/sh\n\$${APPDIR}/usr/bin/tildefriends run -z \$$APPDIR/usr/share/tildefriends/data.zip" > out/tildefriends.AppDir/AppRun
@chmod +x out/tildefriends.AppDir/AppRun
@cd out; ./appimagetool --appimage-extract; cd ..
@cd out; unset SOURCE_DATE_EPOCH; PATH=$$PATH:squashfs-root/usr/bin ARCH=x86_64 squashfs-root/usr/bin/appimagetool -u 'zsync|https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage.zsync' tildefriends.AppDir tildefriends-x86_64.AppImage; cd ..
appimage: out/tildefriends-x86_64.AppImage appimage: out/tildefriends-x86_64.AppImage
.PHONY: appimage .PHONY: appimage

View File

@ -19,24 +19,8 @@ Scuttlebutt, as well as a platform for writing and running web applications.
Builds on Linux (x86_64 and aarch64), MacOS, OpenBSD, and Haiku. Builds for Builds on Linux (x86_64 and aarch64), MacOS, OpenBSD, and Haiku. Builds for
all of those host platforms plus mingw64, iOS, and android. all of those host platforms plus mingw64, iOS, and android.
Tilde Friends uses git submodules, so either: 1. Requires openssl (`libssl-dev`, in debian-speak). All other dependencies
are kept up to date in the tree.
```
git clone --recurse-submodules https://dev.tildefriends.net/cory/tildefriends.git
```
or:
```
git clone https://dev.tildefriends.net/cory/tildefriends.git
cd tildefriends
git submodule update --init --recursive
```
The `.tar.xz` source releases are all-inclusive.
1. On Linux only, system OpenSSL libraries (`libssl-dev`, in debian-speak) are
assumed to be available.
2. To build, run `make debug` or `make release`. An executable will be 2. To build, run `make debug` or `make release`. An executable will be
generated in a subdirectory of `out/`. generated in a subdirectory of `out/`.
3. It's possible to build for Android, iOS, and Windows on Linux, if you have 3. It's possible to build for Android, iOS, and Windows on Linux, if you have

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{ {
"type": "tildefriends-app", "type": "tildefriends-app",
"emoji": "🪪", "emoji": "🪪",
"previous": "&5kw/2PgcySwOYCmAkjHTR2xTkIx3i7UjQmtQ8MfgWw8=.sha256" "previous": "&zxsmzdLKsiG/WZt/Gw7JOxepgypoktNNbIyWiyFiJVc=.sha256"
} }

View File

@ -1,7 +1,5 @@
import * as tfrpc from '/tfrpc.js'; import * as tfrpc from '/tfrpc.js';
const is_admin = core.user?.credentials?.permissions?.administration;
tfrpc.register(async function get_private_key(id) { tfrpc.register(async function get_private_key(id) {
return bip39Words(await ssb.getPrivateKey(id)); return bip39Words(await ssb.getPrivateKey(id));
}); });
@ -17,9 +15,6 @@ tfrpc.register(async function delete_id(id) {
tfrpc.register(async function reload() { tfrpc.register(async function reload() {
await main(); await main();
}); });
tfrpc.register(async function make_server(id) {
return await ssb.swapWithServerIdentity(id);
});
async function main() { async function main() {
let ids = await ssb.getIdentities(); let ids = await ssb.getIdentities();
@ -104,16 +99,6 @@ async function main() {
alert('Error deleting ID: ' + e); alert('Error deleting ID: ' + e);
} }
} }
handler.make_server = async function make_server(event) {
let id = event.srcElement.dataset.id;
try {
if (confirm('Are you sure you want to make "' + id + '" the server identity?\\n\\nFor it to take effect, you will need to both sign in again and restart Tilde Friends.')) {
await tfrpc.rpc.make_server(id);
}
} catch (e) {
alert('Error making server ID: ' + e);
}
}
</script> </script>
<header class="w3-theme w3-padding"><h1>SSB Identity Management</h1></header> <header class="w3-theme w3-padding"><h1>SSB Identity Management</h1></header>
<div class="w3-card-4 w3-margin"> <div class="w3-card-4 w3-margin">
@ -132,14 +117,13 @@ async function main() {
<div class="w3-card-4 w3-margin"> <div class="w3-card-4 w3-margin">
<header class="w3-container w3-theme-l2"><h2>Identities</h2></header> <header class="w3-container w3-theme-l2"><h2>Identities</h2></header>
<ul class="w3-ul">` + <ul class="w3-ul">` +
(ids ?? []) ids
.map( .map(
( (
id id
) => `<li style="overflow: hidden; text-wrap: nowrap; text-overflow: ellipsis"> ) => `<li style="overflow: hidden; text-wrap: nowrap; text-overflow: ellipsis">
<button onclick="handler.export_id(event)" data-id="${id}" class="w3-button w3-theme">Export Identity</button> <button onclick="handler.export_id(event)" data-id="${id}" class="w3-button w3-theme">Export Identity</button>
<button onclick="handler.delete_id(event)" data-id="${id}" class="w3-button w3-theme">Delete Identity</button> <button onclick="handler.delete_id(event)" data-id="${id}" class="w3-button w3-theme">Delete Identity</button>
${is_admin && id != server_id ? `<button onclick="handler.make_server(event)" data-id="${id}" class="w3-button w3-theme">Make Server Identity</button>` : ''}
${id}${id == server_id ? ' <div class="w3-tag w3-theme-l4 w3-round">🖥 local server</div>' : ''} ${id}${id == server_id ? ' <div class="w3-tag w3-theme-l4 w3-round">🖥 local server</div>' : ''}
</li>` </li>`
) )

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{ {
"type": "tildefriends-app", "type": "tildefriends-app",
"emoji": "🐌", "emoji": "🐌",
"previous": "&CsZ2FBYY9awXNPPHAhTlrOHuKlGU6RXZJ3UTV3UQRIE=.sha256" "previous": "&7L314QLuVl8kNbFIWuXXeLqIVefUe5S66WvEmOMQb2U=.sha256"
} }

View File

@ -103,9 +103,6 @@ tfrpc.register(async function encrypt(id, recipients, content) {
tfrpc.register(async function getActiveIdentity() { tfrpc.register(async function getActiveIdentity() {
return await ssb.getActiveIdentity(); return await ssb.getActiveIdentity();
}); });
tfrpc.register(async function sync() {
return await ssb.sync();
});
core.register('onBroadcastsChanged', async function () { core.register('onBroadcastsChanged', async function () {
await tfrpc.rpc.set('broadcasts', await ssb.getBroadcasts()); await tfrpc.rpc.set('broadcasts', await ssb.getBroadcasts());
}); });

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -180,9 +180,6 @@ class TfComposeElement extends LitElement {
break; break;
} }
} }
event.preventDefault();
document.execCommand('insertText', false, event.clipboardData.getData('text/plain'));
} }
async submit() { async submit() {

View File

@ -73,17 +73,16 @@ class TfMessageElement extends LitElement {
} }
} }
if (this.message?.votes?.length) { if (this.message?.votes?.length) {
return html` <div class="w3-container"> return html`
<div <div class="w3-container">
class="w3-button w3-bar w3-padding-small" <div class="w3-button w3-bar w3-padding-small" @click=${this.show_reactions}>
@click=${this.show_reactions}
>
${(this.message.votes || []).map( ${(this.message.votes || []).map(
(vote) => html` (vote) => html`
<span <span
class="w3-bar-item w3-padding-small" class="w3-bar-item w3-padding-small"
title="${this.users[vote.author]?.name ?? title="${this.users[vote.author]?.name ?? vote.author} ${new Date(
vote.author} ${new Date(vote.timestamp)}" vote.timestamp
)}"
> >
${normalize_expression(vote.content.vote.expression)} ${normalize_expression(vote.content.vote.expression)}
</span> </span>

View File

@ -27,9 +27,8 @@ class TfReactionsModalElement extends LitElement {
? html` <div ? html` <div
class="w3-modal w3-animate-opacity" class="w3-modal w3-animate-opacity"
style="display: block; box-sizing: border-box" style="display: block; box-sizing: border-box"
@click=${this.clear}
> >
<div class="w3-modal-content w3-card-4 w3-theme-d1" onclick="event.stopPropagation()"> <div class="w3-modal-content w3-card-4 w3-theme-d1">
<div class="w3-container w3-padding"> <div class="w3-container w3-padding">
<header class="w3-container"> <header class="w3-container">
<h2>Reactions</h2> <h2>Reactions</h2>

View File

@ -136,9 +136,7 @@ class TfTabConnectionsElement extends LitElement {
<div> <div>
${requests.map( ${requests.map(
(x) => html` (x) => html`
<span <span class="w3-tag w3-small"
class=${'w3-tag w3-small ' +
(x.active ? 'w3-theme-l3' : 'w3-theme-d3')}
>${x.request_number > 0 ? '🟩' : '🟥'} ${x.name} >${x.request_number > 0 ? '🟩' : '🟥'} ${x.name}
<span <span
class="w3-badge w3-white" class="w3-badge w3-white"
@ -158,20 +156,10 @@ class TfTabConnectionsElement extends LitElement {
`; `;
} }
refresh() {
tfrpc.rpc.sync();
}
render() { render() {
let self = this; let self = this;
return html` return html`
<div class="w3-container" style="box-sizing: border-box"> <div class="w3-container" style="box-sizing: border-box">
<button
class="w3-button w3-theme-l3 w3-circle w3-ripple w3-large"
@click=${this.refresh}
>
🔃
</button>
<h2>New Connection</h2> <h2>New Connection</h2>
<textarea class="w3-input w3-theme-d1" id="code"></textarea> <textarea class="w3-input w3-theme-d1" id="code"></textarea>
<button <button

View File

@ -37,7 +37,7 @@ class TfUserElement extends LitElement {
if (image_link !== undefined) { if (image_link !== undefined) {
image = html`<img image = html`<img
class="w3-circle" class="w3-circle"
style="width: 2em; height: 2em; vertical-align: middle; object-fit: cover" style="width: 2em; height: 2em; vertical-align: middle"
src="/${image_link}/view" src="/${image_link}/view"
/>`; />`;
} }

View File

@ -1,5 +1,5 @@
{ {
"type": "tildefriends-app", "type": "tildefriends-app",
"emoji": "👋", "emoji": "👋",
"previous": "&7gFmLW5zSMhmxWWY1+jeRcHdullgujSqGJg94lVgr1k=.sha256" "previous": "&7Pqk5nBAcbjzp0etv6WgiyTD3UF++ID0mW6qIbhwt3s=.sha256"
} }

View File

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="48px" height="48px" id="svg3832" version="1.1" inkscape:version="0.47 r22583" sodipodi:docname="appimage-assistant_alt3.svg">
<defs id="defs3834">
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3308-4-6-931-761-0" id="linearGradient2975" gradientUnits="userSpaceOnUse" x1="24.3125" y1="22.96875" x2="24.3125" y2="41.03125"/>
<linearGradient id="linearGradient3308-4-6-931-761-0">
<stop id="stop2919-2" style="stop-color:#ffffff;stop-opacity:1" offset="0"/>
<stop id="stop2921-76" style="stop-color:#ffffff;stop-opacity:0" offset="1"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4222" id="linearGradient2979" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,0.3704967,-0.3617496,0,33.508315,6.1670925)" x1="7.6485429" y1="26.437023" x2="41.861729" y2="26.437023"/>
<linearGradient id="linearGradient4222">
<stop id="stop4224" style="stop-color:#ffffff;stop-opacity:1" offset="0"/>
<stop id="stop4226" style="stop-color:#ffffff;stop-opacity:0" offset="1"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3308-4-6-931-761" id="linearGradient2982" gradientUnits="userSpaceOnUse" gradientTransform="translate(0,0.9999987)" x1="23.99999" y1="4.999989" x2="23.99999" y2="43"/>
<linearGradient id="linearGradient3308-4-6-931-761">
<stop id="stop2919" style="stop-color:#ffffff;stop-opacity:1" offset="0"/>
<stop id="stop2921" style="stop-color:#ffffff;stop-opacity:0" offset="1"/>
</linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient3575" id="radialGradient2985" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,1.0262008,-1.6561124,9.4072203e-4,-56.097482,-45.332325)" cx="48.42384" cy="-48.027504" fx="48.42384" fy="-48.027504" r="38.212933"/>
<linearGradient id="linearGradient3575">
<stop id="stop3577" style="stop-color:#fafafa;stop-opacity:1" offset="0"/>
<stop id="stop3579" style="stop-color:#e6e6e6;stop-opacity:1" offset="1"/>
</linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient3993" id="radialGradient2990" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,2.0478765,-2.7410544,-8.6412258e-8,47.161382,-8.837436)" cx="9.3330879" cy="8.4497671" fx="9.3330879" fy="8.4497671" r="19.99999"/>
<linearGradient id="linearGradient3993">
<stop offset="0" style="stop-color:#a3c0d0;stop-opacity:1" id="stop3995"/>
<stop offset="1" style="stop-color:#427da1;stop-opacity:1" id="stop4001"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient2508" id="linearGradient2992" gradientUnits="userSpaceOnUse" gradientTransform="translate(0,0.9674382)" x1="14.048676" y1="44.137306" x2="14.048676" y2="4.0000005"/>
<linearGradient id="linearGradient2508">
<stop offset="0" style="stop-color:#2e4a5a;stop-opacity:1" id="stop2510"/>
<stop offset="1" style="stop-color:#6e8796;stop-opacity:1" id="stop2512"/>
</linearGradient>
<radialGradient cx="4.9929786" cy="43.5" r="2.5" fx="4.9929786" fy="43.5" id="radialGradient2873-966-168" xlink:href="#linearGradient3688-166-749" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2.003784,0,0,1.4,27.98813,-17.4)"/>
<linearGradient id="linearGradient3688-166-749">
<stop id="stop2883" style="stop-color:#181818;stop-opacity:1" offset="0"/>
<stop id="stop2885" style="stop-color:#181818;stop-opacity:0" offset="1"/>
</linearGradient>
<radialGradient cx="4.9929786" cy="43.5" r="2.5" fx="4.9929786" fy="43.5" id="radialGradient2875-742-326" xlink:href="#linearGradient3688-464-309" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2.003784,0,0,1.4,-20.01187,-104.4)"/>
<linearGradient id="linearGradient3688-464-309">
<stop id="stop2889" style="stop-color:#181818;stop-opacity:1" offset="0"/>
<stop id="stop2891" style="stop-color:#181818;stop-opacity:0" offset="1"/>
</linearGradient>
<linearGradient x1="25.058096" y1="47.027729" x2="25.058096" y2="39.999443" id="linearGradient2877-634-617" xlink:href="#linearGradient3702-501-757" gradientUnits="userSpaceOnUse"/>
<linearGradient id="linearGradient3702-501-757">
<stop id="stop2895" style="stop-color:#181818;stop-opacity:0" offset="0"/>
<stop id="stop2897" style="stop-color:#181818;stop-opacity:1" offset="0.5"/>
<stop id="stop2899" style="stop-color:#181818;stop-opacity:0" offset="1"/>
</linearGradient>
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="7" inkscape:cx="24" inkscape:cy="24" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" inkscape:window-width="603" inkscape:window-height="484" inkscape:window-x="417" inkscape:window-y="162" inkscape:window-maximized="0"/>
<metadata id="metadata3837">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer">
<g style="display:inline" id="g2036" transform="matrix(1.1,0,0,0.4444449,-2.4000022,25.11107)">
<g style="opacity:0.4" id="g3712" transform="matrix(1.052632,0,0,1.285713,-1.263158,-13.42854)">
<rect style="fill:url(#radialGradient2873-966-168);fill-opacity:1;stroke:none" id="rect2801" y="40" x="38" height="7" width="5"/>
<rect style="fill:url(#radialGradient2875-742-326);fill-opacity:1;stroke:none" id="rect3696" transform="scale(-1,-1)" y="-47" x="-10" height="7" width="5"/>
<rect style="fill:url(#linearGradient2877-634-617);fill-opacity:1;stroke:none" id="rect3700" y="40" x="10" height="7.0000005" width="28"/>
</g>
</g>
<rect style="fill:url(#radialGradient2990);fill-opacity:1;stroke:url(#linearGradient2992);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" id="rect5505" y="5.4674392" x="4.5" ry="2.2322156" rx="2.2322156" height="39" width="39"/>
<path style="opacity:0.05;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path4294-1" d="m 21,6.9687498 a 2.0165107,2.0165107 0 0 0 -2.03125,2.03125 l 0,3.9687502 -1.15625,0 a 2.0165107,2.0165107 0 0 0 -1.5,3.375 l 5.0625,5.75 c -0.06312,0.110777 -0.178724,0.246032 -0.21875,0.34375 -0.195898,0.478256 -0.25,0.83653 -0.25,1.21875 l 0,0.125 L 20.8125,23.6875 C 20.534322,23.409323 20.213169,23.162739 19.71875,22.96875 19.47154,22.87176 19.185456,22.791748 18.75,22.8125 c -0.435456,0.02075 -1.054055,0.210302 -1.46875,0.625 L 15.75,24.96875 c -0.414689,0.414689 -0.604245,1.033294 -0.625,1.46875 -0.02075,0.435456 0.05925,0.721537 0.15625,0.96875 C 15.475241,27.900677 15.721817,28.221821 16,28.5 l 0.09375,0.09375 -0.125,0 c -0.382218,0 -0.740493,0.0541 -1.21875,0.25 -0.239128,0.09795 -0.538285,0.214988 -0.84375,0.53125 -0.305465,0.316262 -0.625,0.914788 -0.625,1.53125 l 0,2.1875 c 0,0.616465 0.319536,1.214989 0.625,1.53125 0.305464,0.316261 0.604622,0.433301 0.84375,0.53125 0.478256,0.195898 0.83653,0.25 1.21875,0.25 l 0.125,0 L 16,35.5 c -0.278175,0.278176 -0.52476,0.599329 -0.71875,1.09375 -0.09699,0.24721 -0.177003,0.533292 -0.15625,0.96875 0.02075,0.435458 0.210304,1.054058 0.625,1.46875 l 1.53125,1.53125 c 0.414691,0.414697 1.033292,0.604245 1.46875,0.625 0.435458,0.02076 0.721537,-0.05926 0.96875,-0.15625 0.494425,-0.19399 0.81557,-0.440568 1.09375,-0.71875 l 0.09375,-0.09375 0,0.125 c 0,0.38222 0.0541,0.740495 0.25,1.21875 0.09795,0.239127 0.214989,0.538285 0.53125,0.84375 0.316261,0.305465 0.914783,0.625 1.53125,0.625 l 2.1875,0 c 0.616466,0 1.214989,-0.319534 1.53125,-0.625 0.316261,-0.305466 0.433302,-0.604622 0.53125,-0.84375 0.195896,-0.478255 0.25,-0.836532 0.25,-1.21875 l 0,-0.125 0.09375,0.09375 c 0.278176,0.278175 0.599329,0.52476 1.09375,0.71875 0.24721,0.09699 0.533292,0.177003 0.96875,0.15625 0.435458,-0.02075 1.054058,-0.210304 1.46875,-0.625 L 32.875,39.03125 C 33.289697,38.616559 33.479245,37.997958 33.5,37.5625 33.52076,37.127042 33.44074,36.840963 33.34375,36.59375 33.14976,36.099325 32.903182,35.77818 32.625,35.5 l -0.09375,-0.09375 0.125,0 c 0.38222,0 0.740494,-0.0541 1.21875,-0.25 0.239128,-0.09795 0.538286,-0.214988 0.84375,-0.53125 0.305464,-0.316262 0.625,-0.914787 0.625,-1.53125 l 0,-2.1875 c 0,-0.61646 -0.319535,-1.214987 -0.625,-1.53125 -0.305465,-0.316263 -0.604621,-0.433301 -0.84375,-0.53125 -0.478257,-0.195898 -0.836532,-0.25 -1.21875,-0.25 l -0.125,0 L 32.625,28.5 c 0.278177,-0.278177 0.52476,-0.599329 0.71875,-1.09375 C 33.44074,27.15904 33.520753,26.872957 33.5,26.4375 33.47925,26.002043 33.289697,25.383443 32.875,24.96875 L 31.34375,23.4375 c -0.414688,-0.414694 -1.03329,-0.604245 -1.46875,-0.625 -0.43546,-0.02076 -0.721537,0.05925 -0.96875,0.15625 -0.494426,0.193991 -0.815572,0.44057 -1.09375,0.71875 l -0.09375,0.09375 0,-0.125 c 0,-0.382218 -0.0541,-0.740493 -0.25,-1.21875 -0.09112,-0.22245 -0.228127,-0.500183 -0.5,-0.78125 l 4.71875,-5.3125 a 2.0165107,2.0165107 0 0 0 -1.5,-3.375 l -1.15625,0 0,-3.9687502 A 2.0165107,2.0165107 0 0 0 27,6.9687498 l -6,0 z M 24.3125,31.25 c 0.427097,0 0.75,0.322904 0.75,0.75 0,0.427096 -0.322903,0.75 -0.75,0.75 -0.427094,0 -0.75,-0.322906 -0.75,-0.75 0,-0.427094 0.322906,-0.75 0.75,-0.75 z"/>
<path style="opacity:0.05;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path4294" d="m 20.90625,8.0312498 a 0.96385067,0.96385067 0 0 0 -0.875,0.96875 l 0,5.0312502 -2.21875,0 A 0.96385067,0.96385067 0 0 0 17.09375,15.625 l 5.78125,6.53125 c -0.158814,0.0616 -0.341836,0.0951 -0.4375,0.1875 -0.169161,0.163386 -0.252971,0.323419 -0.3125,0.46875 -0.119058,0.290663 -0.15625,0.566746 -0.15625,0.84375 l 0,1.65625 C 21.718163,25.40233 21.485871,25.509772 21.25,25.625 l -1.1875,-1.1875 c -0.199651,-0.19965 -0.421433,-0.352095 -0.71875,-0.46875 -0.148659,-0.05833 -0.329673,-0.104846 -0.5625,-0.09375 -0.232827,0.0111 -0.53583,0.09833 -0.75,0.3125 L 16.5,25.71875 c -0.214168,0.214168 -0.301403,0.517173 -0.3125,0.75 -0.0111,0.232827 0.03542,0.41384 0.09375,0.5625 0.116655,0.297321 0.269096,0.519099 0.46875,0.71875 l 1.1875,1.1875 c -0.115228,0.235871 -0.222668,0.468163 -0.3125,0.71875 l -1.65625,0 c -0.277003,0 -0.553087,0.03719 -0.84375,0.15625 -0.145332,0.05953 -0.305363,0.143338 -0.46875,0.3125 -0.163387,0.169162 -0.3125,0.46403 -0.3125,0.78125 l 0,2.1875 c 0,0.317221 0.149114,0.612089 0.3125,0.78125 0.163386,0.169161 0.323419,0.252971 0.46875,0.3125 0.290663,0.119058 0.566746,0.15625 0.84375,0.15625 l 1.65625,0 c 0.08983,0.250587 0.197272,0.482879 0.3125,0.71875 L 16.75,36.25 c -0.199649,0.19965 -0.352095,0.421432 -0.46875,0.71875 -0.05833,0.148659 -0.104846,0.329672 -0.09375,0.5625 0.0111,0.232828 0.09833,0.535831 0.3125,0.75 l 1.53125,1.53125 c 0.214168,0.214172 0.517172,0.301403 0.75,0.3125 0.232828,0.0111 0.41384,-0.03542 0.5625,-0.09375 0.29732,-0.116655 0.519098,-0.269096 0.71875,-0.46875 L 21.25,38.375 c 0.235871,0.115228 0.468164,0.222668 0.71875,0.3125 l 0,1.65625 c 0,0.277003 0.03719,0.553087 0.15625,0.84375 0.05953,0.145331 0.143339,0.305364 0.3125,0.46875 0.169161,0.163386 0.464028,0.3125 0.78125,0.3125 l 2.1875,0 c 0.317221,0 0.612089,-0.149113 0.78125,-0.3125 0.169161,-0.163387 0.252971,-0.323419 0.3125,-0.46875 0.119057,-0.290663 0.15625,-0.566748 0.15625,-0.84375 l 0,-1.65625 c 0.250586,-0.08983 0.482879,-0.197272 0.71875,-0.3125 l 1.1875,1.1875 c 0.19965,0.199649 0.421432,0.352095 0.71875,0.46875 0.148659,0.05833 0.329672,0.104846 0.5625,0.09375 0.232828,-0.0111 0.535831,-0.09833 0.75,-0.3125 L 32.125,38.28125 c 0.214172,-0.214168 0.301403,-0.517172 0.3125,-0.75 0.0111,-0.232828 -0.03542,-0.41384 -0.09375,-0.5625 C 32.227095,36.67143 32.074654,36.449652 31.875,36.25 L 30.6875,35.0625 C 30.802728,34.82663 30.910168,34.594337 31,34.34375 l 1.65625,0 c 0.277004,0 0.553087,-0.03719 0.84375,-0.15625 0.145332,-0.05953 0.305364,-0.143339 0.46875,-0.3125 0.163386,-0.169161 0.3125,-0.46403 0.3125,-0.78125 l 0,-2.1875 c 0,-0.317219 -0.149114,-0.612088 -0.3125,-0.78125 C 33.805364,29.955838 33.645332,29.872029 33.5,29.8125 33.209336,29.693442 32.933253,29.65625 32.65625,29.65625 l -1.65625,0 C 30.91017,29.405663 30.802728,29.17337 30.6875,28.9375 L 31.875,27.75 c 0.19965,-0.19965 0.352095,-0.421432 0.46875,-0.71875 0.05833,-0.148659 0.104846,-0.329672 0.09375,-0.5625 -0.0111,-0.232828 -0.09833,-0.535831 -0.3125,-0.75 L 30.59375,24.1875 c -0.214167,-0.21417 -0.517171,-0.301403 -0.75,-0.3125 -0.232829,-0.0111 -0.41384,0.03542 -0.5625,0.09375 -0.29732,0.116656 -0.519099,0.269097 -0.71875,0.46875 L 27.375,25.625 c -0.235871,-0.115228 -0.468163,-0.222668 -0.71875,-0.3125 l 0,-1.65625 c 0,-0.277003 -0.03719,-0.553087 -0.15625,-0.84375 -0.05953,-0.145332 -0.143338,-0.305363 -0.3125,-0.46875 -0.169162,-0.163387 -0.46403,-0.3125 -0.78125,-0.3125 l -0.15625,0 5.65625,-6.40625 A 0.96385067,0.96385067 0 0 0 30.1875,14.03125 l -2.21875,0 0,-5.0312502 A 0.96385067,0.96385067 0 0 0 27,8.0312498 l -6,0 a 0.96385067,0.96385067 0 0 0 -0.09375,0 z M 24.3125,30.1875 c 1.002113,0 1.8125,0.810388 1.8125,1.8125 0,1.002112 -0.810387,1.8125 -1.8125,1.8125 C 23.31039,33.8125 22.5,33.002111 22.5,32 c 0,-1.002111 0.81039,-1.8125 1.8125,-1.8125 z"/>
<path style="fill:url(#radialGradient2985);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path2317" d="M 21,8.9999996 21,15 17.8125,15 24,22 30.1875,15 27,15 l 0,-6.0000004 -6,0 z M 23.21875,23 c -0.172892,0 -0.28125,0.294922 -0.28125,0.65625 l 0,2.28125 C 22.24145,26.095996 21.585954,26.379869 21,26.75 l -1.625,-1.625 c -0.255498,-0.255497 -0.533998,-0.372253 -0.65625,-0.25 l -1.53125,1.53125 c -0.122254,0.122254 -0.0055,0.400753 0.25,0.65625 l 1.625,1.625 c -0.37013,0.585953 -0.654003,1.24145 -0.8125,1.9375 l -2.28125,0 c -0.361328,0 -0.65625,0.108357 -0.65625,0.28125 l 0,2.1875 c 0,0.172892 0.294922,0.28125 0.65625,0.28125 l 2.28125,0 c 0.158497,0.69605 0.44237,1.351546 0.8125,1.9375 l -1.625,1.625 c -0.255497,0.255498 -0.372254,0.533997 -0.25,0.65625 l 1.53125,1.53125 c 0.122252,0.122254 0.400752,0.0055 0.65625,-0.25 L 21,37.25 c 0.585954,0.37013 1.24145,0.654002 1.9375,0.8125 l 0,2.28125 C 22.9375,40.705077 23.045858,41 23.21875,41 l 2.1875,0 c 0.172893,0 0.28125,-0.294924 0.28125,-0.65625 l 0,-2.28125 c 0.69605,-0.158498 1.351546,-0.44237 1.9375,-0.8125 l 1.625,1.625 c 0.255498,0.255497 0.533997,0.372254 0.65625,0.25 l 1.53125,-1.53125 c 0.122254,-0.122252 0.0055,-0.400752 -0.25,-0.65625 l -1.625,-1.625 c 0.370129,-0.585954 0.654003,-1.24145 0.8125,-1.9375 l 2.28125,0 c 0.361329,0 0.65625,-0.108358 0.65625,-0.28125 l 0,-2.1875 c 0,-0.172893 -0.294921,-0.28125 -0.65625,-0.28125 l -2.28125,0 c -0.158497,-0.69605 -0.442371,-1.351547 -0.8125,-1.9375 l 1.625,-1.625 c 0.255497,-0.255497 0.372254,-0.533997 0.25,-0.65625 L 29.90625,24.875 C 29.783997,24.752745 29.505498,24.8695 29.25,25.125 l -1.625,1.625 c -0.585954,-0.370131 -1.24145,-0.654004 -1.9375,-0.8125 l 0,-2.28125 C 25.6875,23.294922 25.579143,23 25.40625,23 l -2.1875,0 z m 1.09375,6.21875 c 1.528616,0 2.78125,1.252635 2.78125,2.78125 0,1.528615 -1.252634,2.78125 -2.78125,2.78125 -1.528614,0 -2.78125,-1.252635 -2.78125,-2.78125 0,-1.528615 1.252636,-2.78125 2.78125,-2.78125 z"/>
<rect style="opacity:0.4;fill:none;stroke:url(#linearGradient2982);stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" id="rect6741" y="6.4999886" x="5.4999981" ry="1.365193" rx="1.365193" height="37.000011" width="36.999985"/>
<path style="fill:none;stroke:url(#linearGradient2979);stroke-width:0.99829447;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" id="path2777" d="M 28.926376,15.466668 24,21.177578 18.963089,15.5 21.5,15.5 l 0,-6.0000004 5,0 0,6.0000004 2.426376,-0.03333 z"/>
<path style="fill:none;stroke:url(#linearGradient2975);stroke-width:1;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path4243" d="m 23.4375,23.46875 c -0.01166,0.05381 -0.03125,0.100205 -0.03125,0.1875 l 0,2.28125 a 0.48185467,0.48185467 0 0 1 -0.375,0.46875 c -0.638467,0.145384 -1.238423,0.407111 -1.78125,0.75 a 0.48185467,0.48185467 0 0 1 -0.59375,-0.0625 l -1.625,-1.625 C 18.9779,25.4154 18.9477,25.40242 18.90625,25.375 l -1.21875,1.21875 c 0.02742,0.04145 0.0404,0.07165 0.09375,0.125 l 1.625,1.625 a 0.48185467,0.48185467 0 0 1 0.0625,0.59375 c -0.342888,0.542826 -0.604615,1.142782 -0.75,1.78125 a 0.48185467,0.48185467 0 0 1 -0.46875,0.375 l -2.28125,0 c -0.08729,0 -0.133695,0.01959 -0.1875,0.03125 l 0,1.75 c 0.05381,0.01166 0.100205,0.03125 0.1875,0.03125 l 2.28125,0 a 0.48185467,0.48185467 0 0 1 0.46875,0.375 c 0.145385,0.638468 0.407112,1.238423 0.75,1.78125 a 0.48185467,0.48185467 0 0 1 -0.0625,0.59375 l -1.625,1.625 c -0.05335,0.05335 -0.06633,0.08355 -0.09375,0.125 l 1.21875,1.21875 c 0.04145,-0.02742 0.07165,-0.0404 0.125,-0.09375 l 1.625,-1.625 A 0.48185467,0.48185467 0 0 1 21.25,36.84375 c 0.542827,0.342888 1.142781,0.604614 1.78125,0.75 a 0.48185467,0.48185467 0 0 1 0.375,0.46875 l 0,2.28125 c 0,0.08729 0.01959,0.133695 0.03125,0.1875 l 1.75,0 c 0.01166,-0.0538 0.03125,-0.100206 0.03125,-0.1875 l 0,-2.28125 a 0.48185467,0.48185467 0 0 1 0.375,-0.46875 c 0.638469,-0.145386 1.238423,-0.407112 1.78125,-0.75 a 0.48185467,0.48185467 0 0 1 0.59375,0.0625 l 1.625,1.625 c 0.05335,0.05335 0.08355,0.06633 0.125,0.09375 l 1.21875,-1.21875 c -0.02742,-0.04145 -0.0404,-0.07165 -0.09375,-0.125 l -1.625,-1.625 a 0.48185467,0.48185467 0 0 1 -0.0625,-0.59375 c 0.342888,-0.542828 0.604615,-1.142783 0.75,-1.78125 a 0.48185467,0.48185467 0 0 1 0.46875,-0.375 l 2.28125,0 c 0.08729,0 0.133695,-0.01959 0.1875,-0.03125 l 0,-1.75 c -0.0538,-0.01166 -0.100204,-0.03125 -0.1875,-0.03125 l -2.28125,0 a 0.48185467,0.48185467 0 0 1 -0.46875,-0.375 c -0.145385,-0.638467 -0.407113,-1.238424 -0.75,-1.78125 a 0.48185467,0.48185467 0 0 1 0.0625,-0.59375 l 1.625,-1.625 c 0.05335,-0.05335 0.06633,-0.08355 0.09375,-0.125 L 29.71875,25.375 c -0.04145,0.02742 -0.07165,0.0404 -0.125,0.09375 l -1.625,1.625 a 0.48185467,0.48185467 0 0 1 -0.59375,0.0625 c -0.542827,-0.342889 -1.142783,-0.604616 -1.78125,-0.75 a 0.48185467,0.48185467 0 0 1 -0.375,-0.46875 l 0,-2.28125 c 0,-0.0873 -0.01959,-0.133695 -0.03125,-0.1875 l -1.75,0 z m 0.875,5.28125 c 1.791829,0 3.25,1.458172 3.25,3.25 0,1.791828 -1.458171,3.25 -3.25,3.25 -1.791827,0 -3.25,-1.458172 -3.25,-3.25 0,-1.791828 1.458173,-3.25 3.25,-3.25 z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,75 +1,124 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Original Author: Unknown (if you are the original creator of the F-Droid button, please contact laura@ind.ie so I can credit you!) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="48" height="48" viewBox="0 0 48.000001 48.000001" id="svg4230" version="1.1" inkscape:version="0.91 r13725" sodipodi:docname="fdroid-logo.svg"> <!-- Author: Created by Laura Kalbag and Released with ❤ by ind.ie (laura@ind.ie) -->
<defs id="defs4232"> <!-- License: This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/. (As attribution is included in this file, you needn't include additional attribution on your site.) -->
<linearGradient inkscape:collect="always" id="linearGradient5212"> <!-- How to use: The original blog post about this SVG button and how I use SVG on the Ind.ie website is at https://ind.ie/blog/f-droid-button/ -->
<stop style="stop-color:#ffffff;stop-opacity:0.09803922" offset="0" id="stop5214"/> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<stop style="stop-color:#ffffff;stop-opacity:0" offset="1" id="stop5216"/> <svg version="1.1" id="button_1_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="1490 188 300 104" enable-background="new 1490 188 300 104" xml:space="preserve">
<g id="get_it_on_f-droid_2_">
<path id="button" d="M1780,292h-280c-5.5,0-10-4.5-10-10v-84c0-5.5,4.5-10,10-10h280c5.5,0,10,4.5,10,10v84
C1790,287.5,1785.5,292,1780,292z"/>
<g id="f-droid_2_">
<path fill="#FFFFFF" d="M1621.2,236.8v3.6v1.2v5h-0.3h-0.6h-2.2c-0.7,0-1-0.3-1.2-1c-0.1-0.4-0.2-1.6-0.3-3.4h-13.5v11.1h13.2v5.5
h-13.2v10.1c0.9,0.2,1.7,0.3,2.6,0.4c0.9,0.2,1.3,0.7,1.3,1.6v3h-3.9h-7.1h-3.9v-3c0-0.9,0.4-1.5,1.3-1.6c0.9-0.2,1.7-0.3,2.6-0.4
V242c-0.9-0.2-1.7-0.3-2.6-0.4c-0.9-0.2-1.3-0.7-1.3-1.6v-3h3.9h22.7h1.2L1621.2,236.8L1621.2,236.8z"/>
<path fill="#FFFFFF" d="M1637.2,256v5.4h-13.5V256H1637.2z"/>
<path fill="#FFFFFF" d="M1676.7,255.6c0,5-1.7,10-5.3,13.5c-3.7,3.6-8.8,5.3-13.9,5.3h-13.9h-3.9v-3c0-0.9,0.4-1.5,1.3-1.6
c0.9-0.2,1.7-0.3,2.6-0.4V242c-0.9-0.2-1.7-0.3-2.6-0.4c-0.9-0.2-1.3-0.7-1.3-1.6v-3h3.9h13.9c5.1,0,10.2,1.6,13.9,5.3
C1675.1,245.6,1676.7,250.7,1676.7,255.6C1676.7,258.4,1676.7,252.9,1676.7,255.6z M1669.6,255.6c0-3.4-0.8-6.9-3.1-9.5
s-5.6-3.7-8.9-3.7h-6.8v26.4h6.8c3.4,0,6.7-1.1,8.9-3.7C1668.8,262.5,1669.6,259,1669.6,255.6z"/>
<path fill="#FFFFFF" d="M1699.7,248.1l-0.9,4.8c-0.2,1.1-1.3,0.9-2.1,0.7c-1-0.3-2.2-0.3-3.1,0c-2.2,0.5-3.7,2.3-4.5,4.2v11.4
c2.3,0.4,2.3,0.4,2.6,0.4c0.9,0.2,1.3,0.7,1.3,1.6v3h-3.9l0,0h-6.5h-3.9v-3c0-0.9,0.4-1.5,1.3-1.6c0.4-0.1,0.4-0.1,2.6-0.4v-16.3
c-2.3-0.4-2.3-0.4-2.6-0.4c-0.9-0.2-1.3-0.7-1.3-1.6v-3h3.9l0,0h3.8c1.1,0,1.7,0.4,1.9,1.6l0.3,3.2c1.1-1.9,2.6-3.7,4.7-4.7
C1695.2,247,1697.8,246.9,1699.7,248.1z"/>
<path fill="#FFFFFF" d="M1719.4,248.3c5.7,2.3,8,8,7.8,13.7c-0.3,5.6-3.4,10.7-9.1,12.3c-5.4,1.5-11.9,0-15.1-4.9
c-3.1-4.6-3.2-11.6-0.3-16.4C1706,247.6,1713.6,246,1719.4,248.3C1721,248.9,1717.8,247.6,1719.4,248.3z M1718.9,267.6
c2-2.8,2-7.1,1.2-10.2c-0.3-1.5-1-2.9-2.2-3.9c-1.3-1-3-1.4-4.6-1.2c-3.5,0.2-5.3,2.7-5.8,5.9c-0.5,3.1-0.5,7.5,1.8,10
C1711.8,270.7,1716.8,270.5,1718.9,267.6C1720,266.2,1717.9,269.1,1718.9,267.6z"/>
<path fill="#FFFFFF" d="M1743.3,271.4v3h-3.9h-6.5h-4v-3c0-0.9,0.4-1.5,1.3-1.6c0.9-0.2,1.7-0.3,2.6-0.4v-16.4
c-0.9-0.2-1.7-0.3-2.6-0.4c-0.9-0.2-1.3-0.7-1.3-1.6v-3h3.9h6.5v21.5c0.9,0.2,1.7,0.3,2.6,0.4
C1742.9,269.9,1743.3,270.5,1743.3,271.4z M1740,241.6c-1,2-3.4,3-5.4,2.2c-2-0.9-3.1-3.3-2.2-5.3c0.9-2.1,3.3-3,5.4-2.2
C1739.9,237.1,1741,239.5,1740,241.6C1739.8,242,1740.3,241,1740,241.6z"/>
<path fill="#FFFFFF" d="M1773.4,274.3h-3.7h-3.9c-0.8,0-1.5-0.3-1.7-1.2l-0.5-2.4c-2.4,2.8-5.9,4.5-9.8,4.1
c-3.8-0.4-6.5-3.2-7.8-6.6c-2.4-6.6-1.3-16.3,5.6-19.8c3.8-1.9,8.5-1.5,11.6,1.5V241c-0.9-0.2-1.7-0.3-2.6-0.4
c-0.9-0.2-1.3-0.7-1.3-1.6v-3h3.9h6.5v33.5c0.8,0.2,1.6,0.3,2.4,0.4c0.9,0.2,1.3,0.7,1.3,1.6V274.3z M1763.3,254.6
c-1.7-2-4.2-2.9-6.7-2.3c-2.5,0.6-3.9,2.8-4.4,5.1c-0.5,2.3-0.5,5-0.1,7.4c0.4,2.3,1.7,4.4,4.1,4.9c2.9,0.5,5.4-1,7.2-3.1V254.6z"
/>
</g>
<g id="get_it_on_2_">
<path fill="#FFFFFF" d="M1597.5,218.2v-2.9h7.6v6.9c-3.7,3.6-11.2,3.9-14.5-0.3c-3.3-4.2-2.4-11.5,2.6-14c2.2-1.1,5.1-1.1,7.3-0.4
s3.8,2.4,4.3,4.7l-3.5,0.7c-0.7-2.5-3.5-3.3-5.8-2.5c-2.2,0.7-3.1,2.8-3.2,4.9c-0.1,2.2,0.3,4.6,2.1,5.9c2.1,1.6,5.1,0.9,7-0.6
v-2.3H1597.5z"/>
<path fill="#FFFFFF" d="M1608.3,224.7v-17.3h13v2.9h-9.4v3.8h8.8v2.9h-8.8v4.8h9.8v2.9L1608.3,224.7L1608.3,224.7z"/>
<path fill="#FFFFFF" d="M1628.6,224.7v-14.4h-5.1v-2.9h13.9v2.9h-5.1v14.5L1628.6,224.7L1628.6,224.7z"/>
<path fill="#FFFFFF" d="M1646.3,224.7v-17.3h3.5v17.3H1646.3z"/>
<path fill="#FFFFFF" d="M1657.1,224.7v-14.4h-5.1v-2.9h13.9v2.9h-5.1v14.5L1657.1,224.7L1657.1,224.7z"/>
<path fill="#FFFFFF" d="M1674.1,216.1c0-1.7,0.3-3.3,0.8-4.4c0.8-1.7,2.2-3.2,3.9-4c2.8-1.1,6.5-1,9,0.9c2.5,1.8,3.4,4.9,3.3,7.8
c-0.1,2.9-1.1,5.8-3.8,7.5c-2.5,1.6-6.1,1.6-8.7,0.3C1675.4,222.7,1674.1,219.4,1674.1,216.1z M1677.8,216c0,2.3,0.7,4.8,3.1,5.6
c2.2,0.9,4.8,0,5.8-2c1-1.9,1-4.9,0.3-6.8c-0.9-2.1-3.1-3.1-5.3-2.7C1678.7,210.6,1677.8,213.4,1677.8,216z"/>
<path fill="#FFFFFF" d="M1693.9,224.7v-17.3h3.4l7.2,11.6v-11.6h3.3v17.3h-3.6l-7.1-11.4v11.4H1693.9z"/>
</g>
<g id="droid_2_">
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="413.9844" y1="440.5436" x2="413.9844" y2="452.6552" gradientTransform="matrix(3.7209 0 0 -3.7209 0 1914.4187)">
<stop offset="0" style="stop-color:#2B6099"/>
<stop offset="0.1299" style="stop-color:#2F69A1"/>
<stop offset="0.3451" style="stop-color:#3B83B6"/>
<stop offset="0.5" style="stop-color:#4699C8"/>
<stop offset="0.9944" style="stop-color:#479ECB"/>
</linearGradient> </linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient5212" id="radialGradient5220" cx="-98.23381" cy="3.4695871" fx="-98.23381" fy="3.4695871" r="22.671185" gradientTransform="matrix(0,1.9747624,-2.117225,3.9784049e-8,8.677247,1199.588)" gradientUnits="userSpaceOnUse"/> <path fill="url(#SVGID_1_)" d="M1570.1,275.2h-59.3c-2.9,0-5.2-2.3-5.2-5.2v-34.7c0-2.9,2.4-5.2,5.2-5.2h59.3
<filter inkscape:collect="always" style="color-interpolation-filters:sRGB" id="filter4175" x="-0.023846937" width="1.0476939" y="-0.02415504" height="1.0483101"> c2.9,0,5.2,2.3,5.2,5.2V270C1575.3,272.8,1572.9,275.2,1570.1,275.2z"/>
<feGaussianBlur inkscape:collect="always" stdDeviation="0.45053152" id="feGaussianBlur4177"/>
</filter> <linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="413.9844" y1="440.5436" x2="413.9844" y2="452.6552" gradientTransform="matrix(3.7209 0 0 -3.7209 0 1914.4187)">
</defs> <stop offset="0" style="stop-color:#2B6099"/>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="11.313708" inkscape:cx="6.4184057" inkscape:cy="25.737489" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" units="px" inkscape:window-width="1920" inkscape:window-height="1009" inkscape:window-x="0" inkscape:window-y="34" inkscape:window-maximized="1" gridtolerance="10000"/> <stop offset="0.5" style="stop-color:#58A4CD"/>
<metadata id="metadata4235"> <stop offset="0.7865" style="stop-color:#7FB8D9"/>
<rdf:RDF> <stop offset="1" style="stop-color:#9EC9E2"/>
<cc:Work rdf:about=""> </linearGradient>
<dc:format>image/svg+xml</dc:format> <path fill="url(#SVGID_2_)" d="M1570.1,231.9c1.9,0,3.5,1.6,3.5,3.5V270c0,1.9-1.6,3.5-3.5,3.5h-59.3c-1.9,0-3.5-1.6-3.5-3.5
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> v-34.7c0-1.9,1.6-3.5,3.5-3.5H1570.1 M1570.1,230.1h-59.3c-2.9,0-5.2,2.3-5.2,5.2V270c0,2.9,2.4,5.2,5.2,5.2h59.3
<dc:title/> c2.9,0,5.2-2.3,5.2-5.2v-34.7C1575.3,232.5,1572.9,230.1,1570.1,230.1L1570.1,230.1z"/>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/"/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(0,-1004.3622)">
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#263238;fill-opacity:0.4;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4175);color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 2.613462,1006.3488 a 1.250125,1.250125 0 0 0 -1.01172,2.0293 l 3.60351,4.6641 c -0.12699,0.3331 -0.20312,0.6915 -0.20312,1.0703 l 0,4 0,2.8652 0,0.1348 c 0,1.662 1.338,3 3,3 l 32,0 c 1.662,0 3,-1.338 3,-3 l 0,-4 0,-2.8652 0,-0.1348 c 0,-0.3803 -0.0771,-0.74 -0.20508,-1.0742 l 3.60156,-4.6602 a 1.250125,1.250125 0 0 0 -1.04882,-2.0273 1.250125,1.250125 0 0 0 -0.92969,0.498 l -3.43164,4.4414 c -0.31022,-0.1079 -0.63841,-0.1777 -0.98633,-0.1777 l -32,0 c -0.34857,0 -0.67757,0.069 -0.98828,0.1777 l -3.4336,-4.4414 a 1.250125,1.250125 0 0 0 -0.96679,-0.5 z m 5.38867,18.7637 c -0.20775,0 -0.40983,0.021 -0.60547,0.061 -1.36951,0.2761 -2.39453,1.4698 -2.39453,2.9101 l 0,0.029 0,19.7793 0,0.029 0,0.1914 c 0,1.662 1.338,3 3,3 l 32,0 c 1.662,0 3,-1.338 3,-3 l 0,-20 0,-0.029 c 0,-1.4403 -1.02502,-2.634 -2.39453,-2.9101 -0.19565,-0.039 -0.39772,-0.061 -0.60547,-0.061 l -32,0 z" id="path4192" inkscape:connector-curvature="0"/>
<g id="g5012">
<g id="g4179" transform="matrix(-1,0,0,1,47.999779,0)">
<path style="fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:#769616;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m 2.5889342,1006.8622 4.25,5.5" id="path4181" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
<path sodipodi:nodetypes="cccccc" inkscape:connector-curvature="0" id="path4183" d="m 2.6113281,1005.6094 c -0.4534623,0.012 -0.7616975,0.189 -0.9807462,0.4486 2.0269314,2.4089 2.368401,2.7916 5.1354735,6.2214 1.0195329,1.319 2.0816026,0.6373 1.0620696,-0.6817 l -4.25,-5.5 c -0.2289894,-0.3056 -0.5850813,-0.478 -0.9667969,-0.4883 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:0.29803923;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path4185" d="m 1.6220992,1006.0705 c -0.1238933,0.1479 -0.561176,0.8046 -0.02249,1.5562 l 4.25,5.5 c 1.0195329,1.319 1.1498748,-0.6123 1.1498748,-0.6123 0,0 -3.7344514,-4.51 -5.3773848,-6.4439 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#263238;fill-opacity:0.2;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
<path sodipodi:nodetypes="cscccc" inkscape:connector-curvature="0" id="path4187" d="m 2.3378905,1005.8443 c -0.438175,0 -0.959862,0.1416 -0.8242183,0.7986 0.103561,0.5016 4.6608262,6.0744 4.6608262,6.0744 1.0195329,1.319 2.4934721,0.6763 1.4739391,-0.6425 l -4.234375,-5.4727 c -0.2602394,-0.29 -0.6085188,-0.7436 -1.076172,-0.7578 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
</g> </g>
<g id="g4955"> <g>
<path sodipodi:nodetypes="cc" inkscape:connector-curvature="0" id="path4945" d="m 2.5889342,1006.8622 4.25,5.5" style="fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:#769616;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/> <path fill="#295384" d="M1540.4,236.6c8.9,0,16.1,7.2,16.1,16c0,8.8-7.2,16-16.1,16s-16.1-7.2-16.1-16S1531.5,236.6,1540.4,236.6
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:0.29803923;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 2.6113281,1005.6094 c -0.4534623,0.012 -0.7616975,0.189 -0.9807462,0.4486 2.0269314,2.4089 2.368401,2.7916 5.1354735,6.2214 1.0195329,1.319 2.0816026,0.6373 1.0620696,-0.6817 l -4.25,-5.5 c -0.2289894,-0.3056 -0.5850813,-0.478 -0.9667969,-0.4883 z" id="path4947" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc"/> M1540.4,235.3c-9.6,0-17.4,7.8-17.4,17.3s7.8,17.3,17.4,17.3s17.4-7.8,17.4-17.3S1550.1,235.3,1540.4,235.3L1540.4,235.3z"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#263238;fill-opacity:0.2;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1.6220992,1006.0705 c -0.1238933,0.1479 -0.561176,0.8046 -0.02249,1.5562 l 4.25,5.5 c 1.0195329,1.319 1.1498748,-0.6123 1.1498748,-0.6123 0,0 -3.7344514,-4.51 -5.3773848,-6.4439 z" id="path4951" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 2.3378905,1005.8443 c -0.438175,0 -0.959862,0.1416 -0.8242183,0.7986 0.103561,0.5016 4.6608262,6.0744 4.6608262,6.0744 1.0195329,1.319 2.4934721,0.6763 1.4739391,-0.6425 l -4.234375,-5.4727 c -0.2602394,-0.29 -0.6085188,-0.7436 -1.076172,-0.7578 z" id="path4925" inkscape:connector-curvature="0" sodipodi:nodetypes="cscccc"/>
</g> </g>
<g transform="translate(42,0)" id="g4967"> <path fill="#295384" d="M1535.4,251.1c1.9-5.7,10.7-3.9,10.2,2.2c-0.5,5.6-8.5,6.2-10.2,1.2c0,0,0,0.1,0,0l0,0
<rect style="opacity:1;fill:#aeea00;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" id="rect4144" width="38" height="13" x="-37" y="1010.3622" rx="3" ry="3"/> c-2.4,0.2-4.7,0.4-7.1,0.6c1.7,10.1,15.3,13.1,21.6,5.3c6.5-8,0.3-20.2-10-19.8c-5.6,0.3-10.5,4.3-11.5,9.8"/>
<rect ry="3" rx="3" y="1013.3622" x="-37" height="10" width="38" id="rect4961" style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/> <path fill="#7B952D" d="M1580.3,198.7l-2-1.6c-0.3-0.3-1-0.3-1.2,0.1l-6.8,7.9c-0.3,0.3-0.3,1,0.1,1.2l2,1.6
<rect ry="3" rx="3" y="1010.3622" x="-37" height="10" width="38" id="rect4963" style="opacity:1;fill:#ffffff;fill-opacity:0.29803923;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/> c0.3,0.3,1,0.3,1.2-0.1l6.8-7.9C1580.7,199.6,1580.6,199,1580.3,198.7z"/>
<rect ry="2.5384617" rx="3" y="1011.3622" x="-37" height="11" width="38" id="rect4965" style="opacity:1;fill:#aeea00;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/> <path fill="#7B952D" d="M1500.6,198.1l2-1.6c0.3-0.3,1-0.3,1.2,0.1l6.8,7.9c0.3,0.3,0.3,1-0.1,1.2l-2,1.6c-0.3,0.3-1,0.3-1.2-0.1
l-6.8-7.9C1500.2,199,1500.3,198.5,1500.6,198.1z"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="413.9844" y1="453.354" x2="413.9844" y2="459.4099" gradientTransform="matrix(3.7209 0 0 -3.7209 0 1914.4187)">
<stop offset="0" style="stop-color:#BCDB52"/>
<stop offset="0.3206" style="stop-color:#C5E358"/>
<stop offset="0.5" style="stop-color:#CDEA5C"/>
<stop offset="0.9944" style="stop-color:#DCF285"/>
</linearGradient>
<path fill="url(#SVGID_3_)" stroke="#7B952D" stroke-miterlimit="10" d="M1572.7,227.5h-64.5c-1,0-1.7-0.8-1.7-1.7v-19.1
c0-1,0.8-1.7,1.7-1.7h64.5c1,0,1.7,0.8,1.7,1.7v19.1C1574.4,226.7,1573.6,227.5,1572.7,227.5z"/>
<g>
<ellipse fill="#FFFFFF" cx="1523" cy="215.4" rx="6.1" ry="6.1"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="409.8439" y1="458.401" x2="408.7539" y2="454.8358" gradientTransform="matrix(3.7209 0 0 -3.7209 0 1914.4187)">
<stop offset="0" style="stop-color:#8BA53D"/>
<stop offset="8.484717e-02" style="stop-color:#94AE45"/>
<stop offset="0.2259" style="stop-color:#AEC65C"/>
<stop offset="0.4048" style="stop-color:#D7ED81"/>
<stop offset="0.4246" style="stop-color:#DCF285"/>
</linearGradient>
<path fill="url(#SVGID_4_)" d="M1523,222.3c-3.8,0-7-3.1-7-6.9c0-3.8,3.1-6.9,7-6.9c3.8,0,7,3.1,7,6.9
C1529.9,219.2,1526.9,222.3,1523,222.3z M1523,210.2c-2.9,0-5.2,2.3-5.2,5.2s2.4,5.2,5.2,5.2s5.2-2.3,5.2-5.2
S1525.9,210.2,1523,210.2z"/>
</g> </g>
<g id="g4979"> <g>
<rect style="opacity:1;fill:#1976d2;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" id="rect4146" width="38" height="26" x="5" y="1024.3622" rx="3" ry="3"/> <ellipse fill="#FFFFFF" cx="1557.8" cy="215.4" rx="6.1" ry="6.1"/>
<rect ry="3" rx="3" y="1037.3622" x="5" height="13" width="38" id="rect4973" style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/>
<rect ry="3" rx="3" y="1024.3622" x="5" height="13" width="38" id="rect4975" style="opacity:1;fill:#ffffff;fill-opacity:0.2;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/> <linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="419.2189" y1="458.401" x2="418.129" y2="454.8359" gradientTransform="matrix(3.7209 0 0 -3.7209 0 1914.4187)">
<rect ry="2.7692308" rx="3" y="1025.3622" x="5" height="24" width="38" id="rect4977" style="opacity:1;fill:#1976d2;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/> <stop offset="0" style="stop-color:#8BA53D"/>
</g> <stop offset="8.484717e-02" style="stop-color:#94AE45"/>
<g transform="translate(0,1013.3622)" id="g4211"> <stop offset="0.2259" style="stop-color:#AEC65C"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0d47a1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 24,17.75 c -2.880662,0 -5.319789,1.984685 -6.033203,4.650391 l 3.212891,0 C 21.734004,21.415044 22.774798,20.75 24,20.75 c 1.812692,0 3.25,1.437308 3.25,3.25 0,1.812693 -1.437308,3.25 -3.25,3.25 -1.307381,0 -2.411251,-0.75269 -2.929688,-1.849609 l -3.154296,0 C 18.558263,28.166146 21.04791,30.25 24,30.25 c 3.434013,0 6.25,-2.815987 6.25,-6.25 0,-3.434012 -2.815987,-6.25 -6.25,-6.25 z" id="path4161" inkscape:connector-curvature="0"/> <stop offset="0.4048" style="stop-color:#D7ED81"/>
<circle style="opacity:1;fill:none;fill-opacity:0.40392157;stroke:#0d47a1;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" id="path4209" cx="24" cy="24" r="9.5500002"/> <stop offset="0.4246" style="stop-color:#DCF285"/>
</g> </linearGradient>
<g id="g4989" transform="translate(0,0.50001738)"> <path fill="url(#SVGID_5_)" d="M1557.8,222.3c-3.8,0-7-3.1-7-6.9c0-3.8,3.1-6.9,7-6.9c3.8,0,7,3.1,7,6.9
<ellipse cy="1016.4872" cx="14.375" id="circle4985" style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117" rx="3.375" ry="3.875"/> C1564.8,219.2,1561.8,222.3,1557.8,222.3z M1557.8,210.2c-2.9,0-5.2,2.3-5.2,5.2s2.4,5.2,5.2,5.2c2.9,0,5.2-2.3,5.2-5.2
<circle style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117" id="path4859" cx="14.375" cy="1016.9872" r="3.375"/> S1560.8,210.2,1557.8,210.2z"/>
</g>
<g transform="translate(19.5,0.50001738)" id="g4171">
<ellipse ry="3.875" rx="3.375" style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117" id="ellipse4175" cx="14.375" cy="1016.4872"/>
<circle r="3.375" cy="1016.9872" cx="14.375" id="circle4177" style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117"/>
</g> </g>
</g> </g>
<path inkscape:connector-curvature="0" id="path5128" d="m 2.613462,1005.5987 a 1.250125,1.250125 0 0 0 -1.01172,2.0293 l 3.60351,4.6641 c -0.12699,0.3331 -0.20312,0.6915 -0.20312,1.0703 l 0,4 0,2.8652 0,0.1348 c 0,1.662 1.338,3 3,3 l 32,0 c 1.662,0 3,-1.338 3,-3 l 0,-4 0,-2.8652 0,-0.1348 c 0,-0.3803 -0.0771,-0.74 -0.20508,-1.0742 l 3.60156,-4.6602 a 1.250125,1.250125 0 0 0 -1.04882,-2.0273 1.250125,1.250125 0 0 0 -0.92969,0.498 l -3.43164,4.4414 c -0.31022,-0.1079 -0.63841,-0.1777 -0.98633,-0.1777 l -32,0 c -0.34857,0 -0.67757,0.069 -0.98828,0.1777 l -3.4336,-4.4414 a 1.250125,1.250125 0 0 0 -0.96679,-0.5 z m 5.38867,18.7637 c -0.20775,0 -0.40983,0.021 -0.60547,0.061 -1.36951,0.2761 -2.39453,1.4698 -2.39453,2.9101 l 0,0.029 0,19.7793 0,0.029 0,0.1914 c 0,1.662 1.338,3 3,3 l 32,0 c 1.662,0 3,-1.338 3,-3 l 0,-20 0,-0.029 c 0,-1.4403 -1.02502,-2.634 -2.39453,-2.9101 -0.19565,-0.039 -0.39772,-0.061 -0.60547,-0.061 l -32,0 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#radialGradient5220);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/> </g>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 511.999 511.999" xml:space="preserve">
<g>
<path style="fill:#32BBFF;" d="M382.369,175.623C322.891,142.356,227.427,88.937,79.355,6.028
C69.372-0.565,57.886-1.429,47.962,1.93l254.05,254.05L382.369,175.623z"/>
<path style="fill:#32BBFF;" d="M47.962,1.93c-1.86,0.63-3.67,1.39-5.401,2.308C31.602,10.166,23.549,21.573,23.549,36v439.96
c0,14.427,8.052,25.834,19.012,31.761c1.728,0.917,3.537,1.68,5.395,2.314L302.012,255.98L47.962,1.93z"/>
<path style="fill:#32BBFF;" d="M302.012,255.98L47.956,510.035c9.927,3.384,21.413,2.586,31.399-4.103
c143.598-80.41,237.986-133.196,298.152-166.746c1.675-0.941,3.316-1.861,4.938-2.772L302.012,255.98z"/>
</g>
<path style="fill:#2C9FD9;" d="M23.549,255.98v219.98c0,14.427,8.052,25.834,19.012,31.761c1.728,0.917,3.537,1.68,5.395,2.314
L302.012,255.98H23.549z"/>
<path style="fill:#29CC5E;" d="M79.355,6.028C67.5-1.8,53.52-1.577,42.561,4.239l255.595,255.596l84.212-84.212
C322.891,142.356,227.427,88.937,79.355,6.028z"/>
<path style="fill:#D93F21;" d="M298.158,252.126L42.561,507.721c10.96,5.815,24.939,6.151,36.794-1.789
c143.598-80.41,237.986-133.196,298.152-166.746c1.675-0.941,3.316-1.861,4.938-2.772L298.158,252.126z"/>
<path style="fill:#FFD500;" d="M488.45,255.98c0-12.19-6.151-24.492-18.342-31.314c0,0-22.799-12.721-92.682-51.809l-83.123,83.123
l83.204,83.205c69.116-38.807,92.6-51.892,92.6-51.892C482.299,280.472,488.45,268.17,488.45,255.98z"/>
<path style="fill:#FFAA00;" d="M470.108,287.294c12.191-6.822,18.342-19.124,18.342-31.314H294.303l83.204,83.205
C446.624,300.379,470.108,287.294,470.108,287.294z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -66,29 +66,10 @@
<a <a
class="w3-button w3-black w3-padding-large" class="w3-button w3-black w3-padding-large"
href="https://dev.tildefriends.net/" href="https://dev.tildefriends.net/"
><i class="fa fa-mug-hot"></i> Development</a ><i class="fa fa-mug-hot"></i> Code</a
> >
<p> <p>
<a <a href="https://f-droid.org/en/packages/com.unprompted.tildefriends.fdroid/"><img src="f-droid.svg" style="height: 3em"></a>
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
href="https://f-droid.org/en/packages/com.unprompted.tildefriends.fdroid/"
><img src="f-droid.svg" style="height: 2em; margin: 0" /> Get it
on F-Droid</a
>
<a
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
href="https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage"
>
<img src="appimage.svg" style="height: 2em; margin: 0" />
Get Linux 64-bit AppImage
</a>
<a
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
href="https://play.google.com/store/apps/details?id=com.unprompted.tildefriends"
>
<img src="googleplay.svg" style="height: 2em; margin: 0" />
Get it on Google Play (Open Testing)
</a>
</p> </p>
</div> </div>
<div class="w3-col l4 m6"> <div class="w3-col l4 m6">
@ -110,31 +91,36 @@
<a href="https://dev.tildefriends.net/cory/tildefriends/releases" <a href="https://dev.tildefriends.net/cory/tildefriends/releases"
>Download</a >Download</a
> >
Tilde Friends or use Tilde Friends and run your own instance, or use
<a href="https://www.tildefriends.net/" <a href="https://www.tildefriends.net/"
>https://www.tildefriends.net/</a >https://www.tildefriends.net/</a
>. >.
</li> </li>
<li>Create an account to identify yourself with that instance.</li> <li>
Create an account to identify yourself with that instance by
username and password.
</li>
<li>
Create an SSB identity in the <b>ssb</b> app. This will generate a
keypair used to identify yourself to other users and sign your
messages so that they can be verified as from you.
</li>
<li> <li>
Describe yourself in your profile in the <b>ssb</b> app. Give Describe yourself in your profile in the <b>ssb</b> app. Give
yourself a name and an avatar if you like. yourself a name and an avatar if you like.
</li> </li>
<li> <li>
Connect to others. Connect to others. You will automatically discover peers on the
<ul> same instance and same network if there are any. Or use
<li>Automatically discover peers on the same network.</li> <a href="https://github.com/staltz/ssb-room/blob/master/FAQ.md"
<li> >rooms</a
Manually connect to rooms and pubs, including >
and pubs to reach more distant users.
<a href="https://www.tildefriends.net/~cory/room/" <a href="https://www.tildefriends.net/~cory/room/"
>tildefriends.net itself</a >tildefriends.net itself</a
>. >
</li> operates as a room, so you can connect and see who else is online
<li> and establish a connection.
Enable <b>Peer Exchange</b> in the <b>admin</b> to discover
internet peers.
</li>
</ul>
</li> </li>
<li>Follow people to grow your network.</li> <li>Follow people to grow your network.</li>
<li> <li>
@ -223,13 +209,8 @@
<!-- Technlology Section --> <!-- Technlology Section -->
<div class="w3-container w3-padding-64 w3-light-grey w3-center"> <div class="w3-container w3-padding-64 w3-light-grey w3-center">
<h1 class="w3-jumbo"><b>Boring Technology</b></h1> <h1 class="w3-jumbo"><b>Trusted Technology</b></h1>
<p> <p>Tilde Friends is built using boring, trusted tech.</p>
Tilde Friends is built using boring, trusted tech. Unless a better
reason presents itself, it strives to use only simple and widely adopted
dependencies in order to keep it easy to build for all sorts of
platforms and maintainable for a very long time.
</p>
<p> <p>
Though of course for building Tilde Friends apps, you are free to use Though of course for building Tilde Friends apps, you are free to use
whatever fits. whatever fits.
@ -266,7 +247,7 @@
<i class="fa fa-lock w3-text-purple w3-jumbo"></i> <i class="fa fa-lock w3-text-purple w3-jumbo"></i>
<p>libsodium</p> <p>libsodium</p>
</a> </a>
<a href="https://github.com/openssl/openssl/releases" class="w3-col s3"> <a href="https://www.openssl.org/" class="w3-col s3">
<i class="fa fa-shield-halved w3-text-green w3-jumbo"></i> <i class="fa fa-shield-halved w3-text-green w3-jumbo"></i>
<p>OpenSSL</p> <p>OpenSSL</p>
</a> </a>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -10,7 +10,7 @@ let gSessionIndex = 0;
* @returns * @returns
*/ */
function makeSessionId() { function makeSessionId() {
return 'session_' + (gSessionIndex++).toString(); return (gSessionIndex++).toString();
} }
/** /**
@ -172,7 +172,7 @@ async function socket(request, response, client) {
0x1 0x1
); );
} else { } else {
process = await core.getProcessBlob( process = await core.getSessionProcessBlob(
blobId, blobId,
sessionId, sessionId,
options options

View File

@ -1782,11 +1782,10 @@ async function sourcePretty() {
let prettier = (await import('/prettier/standalone.mjs')).default; let prettier = (await import('/prettier/standalone.mjs')).default;
let babel = (await import('/prettier/babel.mjs')).default; let babel = (await import('/prettier/babel.mjs')).default;
let estree = (await import('/prettier/estree.mjs')).default; let estree = (await import('/prettier/estree.mjs')).default;
let prettier_html = (await import('/prettier/html.mjs')).default;
let source = gEditor.state.doc.toString(); let source = gEditor.state.doc.toString();
let formatted = await prettier.format(source, { let formatted = await prettier.format(source, {
parser: gCurrentFile?.toLowerCase()?.endsWith('.html') ? 'html' : 'babel', parser: 'babel',
plugins: [babel, estree, prettier_html], plugins: [babel, estree],
trailingComma: 'es5', trailingComma: 'es5',
useTabs: true, useTabs: true,
semi: true, semi: true,
@ -1821,8 +1820,8 @@ function toggleVisibleWhitespace() {
.cm-highlightTab { .cm-highlightTab {
background-image: unset !important; background-image: unset !important;
} }
.cm-highlightSpace { .cm-highlightSpace:before {
background-image: unset !important; content: unset !important;
} }
`; `;
window.localStorage.setItem('visible_whitespace', '1'); window.localStorage.setItem('visible_whitespace', '1');

View File

@ -87,6 +87,10 @@ const k_global_settings = {
}, },
}; };
let gGlobalSettings = {
index: '/~core/apps/',
};
let kPingInterval = 60 * 1000; let kPingInterval = 60 * 1000;
/** /**
@ -258,6 +262,23 @@ function postMessageInternal(from, to, message) {
} }
} }
/**
* TODOC
* @param {*} blobId
* @param {*} session
* @param {*} options
* @returns
*/
async function getSessionProcessBlob(blobId, session, options) {
let actualOptions = {timeout: kPingInterval};
if (options) {
for (let i in options) {
actualOptions[i] = options[i];
}
}
return getProcessBlob(blobId, 'session_' + session, actualOptions);
}
/** /**
* TODOC * TODOC
* @param {*} blobId * @param {*} blobId
@ -285,7 +306,7 @@ async function getProcessBlob(blobId, key, options) {
} }
process.lastActive = Date.now(); process.lastActive = Date.now();
process.lastPing = null; process.lastPing = null;
process.timeout = kPingInterval; process.timeout = options.timeout;
process.ready = new Promise(function (resolve, reject) { process.ready = new Promise(function (resolve, reject) {
resolveReady = resolve; resolveReady = resolve;
rejectReady = reject; rejectReady = reject;
@ -324,59 +345,59 @@ async function getProcessBlob(blobId, key, options) {
return []; return [];
} }
}, },
permissionsGranted: async function () { permissionsGranted: function () {
let user = process?.credentials?.session?.name; let user = process?.credentials?.session?.name;
let settings = await loadSettings();
if ( if (
user && user &&
options?.packageOwner && options?.packageOwner &&
options?.packageName && options?.packageName &&
settings.userPermissions && gGlobalSettings.userPermissions &&
settings.userPermissions[user] && gGlobalSettings.userPermissions[user] &&
settings.userPermissions[user][options.packageOwner] gGlobalSettings.userPermissions[user][options.packageOwner]
) { ) {
return settings.userPermissions[user][ return gGlobalSettings.userPermissions[user][
options.packageOwner options.packageOwner
][options.packageName]; ][options.packageName];
} }
}, },
allPermissionsGranted: async function () { allPermissionsGranted: function () {
let user = process?.credentials?.session?.name; let user = process?.credentials?.session?.name;
let settings = await loadSettings();
if ( if (
user && user &&
options?.packageOwner && options?.packageOwner &&
options?.packageName && options?.packageName &&
settings.userPermissions && gGlobalSettings.userPermissions &&
settings.userPermissions[user] gGlobalSettings.userPermissions[user]
) { ) {
return settings.userPermissions[user]; return gGlobalSettings.userPermissions[user];
} }
}, },
permissionsForUser: async function (user) { permissionsForUser: function (user) {
let settings = await loadSettings(); return (
return settings?.permissions?.[user] ?? []; (gGlobalSettings?.permissions
? gGlobalSettings.permissions[user]
: []) ?? []
);
}, },
apps: (user) => getApps(user, process), apps: (user) => getApps(user, process),
getSockets: getSockets, getSockets: getSockets,
permissionTest: async function (permission) { permissionTest: function (permission) {
let user = process?.credentials?.session?.name; let user = process?.credentials?.session?.name;
let settings = await loadSettings();
if (!user || !options?.packageOwner || !options?.packageName) { if (!user || !options?.packageOwner || !options?.packageName) {
return; return;
} else if ( } else if (
settings.userPermissions && gGlobalSettings.userPermissions &&
settings.userPermissions[user] && gGlobalSettings.userPermissions[user] &&
settings.userPermissions[user][options.packageOwner] && gGlobalSettings.userPermissions[user][options.packageOwner] &&
settings.userPermissions[user][options.packageOwner][ gGlobalSettings.userPermissions[user][options.packageOwner][
options.packageName options.packageName
] && ] &&
settings.userPermissions[user][options.packageOwner][ gGlobalSettings.userPermissions[user][options.packageOwner][
options.packageName options.packageName
][permission] !== undefined ][permission] !== undefined
) { ) {
if ( if (
settings.userPermissions[user][options.packageOwner][ gGlobalSettings.userPermissions[user][options.packageOwner][
options.packageName options.packageName
][permission] ][permission]
) { ) {
@ -387,9 +408,9 @@ async function getProcessBlob(blobId, key, options) {
} else if (process.app) { } else if (process.app) {
return process.app return process.app
.makeFunction(['requestPermission'])(permission) .makeFunction(['requestPermission'])(permission)
.then(async function (value) { .then(function (value) {
if (value == 'allow') { if (value == 'allow') {
await ssb.setUserPermission( storePermission(
user, user,
options.packageOwner, options.packageOwner,
options.packageName, options.packageName,
@ -401,7 +422,7 @@ async function getProcessBlob(blobId, key, options) {
} else if (value == 'allow once') { } else if (value == 'allow once') {
return true; return true;
} else if (value == 'deny') { } else if (value == 'deny') {
await ssb.setUserPermission( storePermission(
user, user,
options.packageOwner, options.packageOwner,
options.packageName, options.packageName,
@ -488,24 +509,23 @@ async function getProcessBlob(blobId, key, options) {
} }
}; };
if (process.credentials?.permissions?.administration) { if (process.credentials?.permissions?.administration) {
imports.core.globalSettingsDescriptions = async function () { imports.core.globalSettingsDescriptions = function () {
let settings = Object.assign({}, k_global_settings); let settings = Object.assign({}, k_global_settings);
for (let [key, value] of Object.entries(await loadSettings())) { for (let [key, value] of Object.entries(gGlobalSettings)) {
if (settings[key]) { if (settings[key]) {
settings[key].value = value; settings[key].value = value;
} }
} }
return settings; return settings;
}; };
imports.core.globalSettingsGet = async function (key) { imports.core.globalSettingsGet = function (key) {
let settings = await loadSettings(); return gGlobalSettings[key];
return settings?.[key];
}; };
imports.core.globalSettingsSet = async function (key, value) { imports.core.globalSettingsSet = async function (key, value) {
print('Setting', key, value); print('Setting', key, value);
let settings = await loadSettings(); await loadSettings();
settings[key] = value; gGlobalSettings[key] = value;
await new Database('core').set('settings', JSON.stringify(settings)); setGlobalSettings(gGlobalSettings);
print('Done.'); print('Done.');
}; };
imports.core.deleteUser = async function (user) { imports.core.deleteUser = async function (user) {
@ -672,24 +692,11 @@ async function getProcessBlob(blobId, key, options) {
); );
} }
}; };
imports.ssb.swapWithServerIdentity = function (id) {
if (
process.credentials &&
process.credentials.session &&
process.credentials.session.name
) {
return ssb.swapWithServerIdentity(
process.credentials.session.name,
id
);
}
};
imports.ssb.addEventListener = undefined; imports.ssb.addEventListener = undefined;
imports.ssb.removeEventListener = undefined; imports.ssb.removeEventListener = undefined;
imports.ssb.getIdentityInfo = undefined; imports.ssb.getIdentityInfo = undefined;
imports.fetch = async function (url, options) { imports.fetch = function (url, options) {
let settings = await loadSettings(); return http.fetch(url, options, gGlobalSettings.fetch_hosts);
return http.fetch(url, options, settings?.fetch_hosts);
}; };
if ( if (
@ -740,22 +747,22 @@ async function getProcessBlob(blobId, key, options) {
); );
}; };
} }
process.sendPermissions = async function sendPermissions() { process.sendPermissions = function sendPermissions() {
process.app.send({ process.app.send({
action: 'permissions', action: 'permissions',
permissions: await imports.core.permissionsGranted(), permissions: imports.core.permissionsGranted(),
}); });
}; };
process.resetPermission = async function resetPermission(permission) { process.resetPermission = function resetPermission(permission) {
let user = process?.credentials?.session?.name; let user = process?.credentials?.session?.name;
await ssb.setUserPermission( storePermission(
user, user,
options?.packageOwner, options?.packageOwner,
options?.packageName, options?.packageName,
permission, permission,
undefined undefined
); );
return process.sendPermissions(); process.sendPermissions();
}; };
process.task.setImports(imports); process.task.setImports(imports);
process.task.activate(); process.task.activate();
@ -788,7 +795,7 @@ async function getProcessBlob(blobId, key, options) {
broadcastEvent('onSessionBegin', [getUser(process, process)]); broadcastEvent('onSessionBegin', [getUser(process, process)]);
if (process.app) { if (process.app) {
process.app.send({action: 'ready', version: version()}); process.app.send({action: 'ready', version: version()});
await process.sendPermissions(); process.sendPermissions();
} }
await process.task.execute({name: appSourceName, source: appSource}); await process.task.execute({name: appSourceName, source: appSource});
resolveReady(process); resolveReady(process);
@ -812,6 +819,20 @@ async function getProcessBlob(blobId, key, options) {
return process; return process;
} }
/**
* TODOC
* @param {*} settings
* @returns
*/
async function setGlobalSettings(settings) {
gGlobalSettings = settings;
try {
return await new Database('core').set('settings', JSON.stringify(settings));
} catch (error) {
print('Error storing settings:', error);
}
}
/** /**
* TODOC * TODOC
* @param {*} response * @param {*} response
@ -932,7 +953,66 @@ async function blobHandler(request, response, blobId, uri) {
} }
let process; let process;
if (uri == '/save') { if (uri == '/view') {
let data;
let match;
let query = form.decodeForm(request.query);
let headers = {
'Content-Security-Policy': k_content_security_policy,
};
if (query.filename && query.filename.match(/^[A-Za-z0-9\.-]*$/)) {
headers['Content-Disposition'] = `attachment; filename=${query.filename}`;
}
if ((match = /^\/\~(\w+)\/(\w+)$/.exec(blobId))) {
let id = await new Database(match[1]).get('path:' + match[2]);
if (id) {
if (request.headers['if-none-match'] === '"' + id + '"') {
headers['Content-Length'] = '0';
response.writeHead(304, headers);
response.end();
} else {
data = await ssb.blobGet(id);
if (match[3]) {
let appObject = JSON.parse(data);
data = appObject.files[match[3]];
}
sendData(
response,
data,
undefined,
Object.assign({etag: '"' + id + '"'}, headers)
);
}
} else {
if (request.headers['if-none-match'] === '"' + blobId + '"') {
headers['Content-Length'] = '0';
response.writeHead(304, headers);
response.end();
} else {
sendData(
response,
data,
undefined,
Object.assign({etag: '"' + blobId + '"'}, headers)
);
}
}
} else {
if (request.headers['if-none-match'] === '"' + blobId + '"') {
headers['Content-Length'] = '0';
response.writeHead(304, headers);
response.end();
} else {
data = await ssb.blobGet(blobId);
sendData(
response,
data,
undefined,
Object.assign({etag: '"' + blobId + '"'}, headers)
);
}
}
} else if (uri == '/save') {
let match; let match;
if ((match = /^\/\~(\w+)\/(\w+)$/.exec(blobId))) { if ((match = /^\/\~(\w+)\/(\w+)$/.exec(blobId))) {
let user = match[1]; let user = match[1];
@ -1137,7 +1217,7 @@ async function loadSettings() {
data[key] = value.default_value; data[key] = value.default_value;
} }
} }
return data; gGlobalSettings = data;
} }
/** /**
@ -1162,9 +1242,9 @@ function sendStats() {
* TODOC * TODOC
*/ */
loadSettings() loadSettings()
.then(function (settings) { .then(function () {
if (tildefriends.https_port && settings.http_redirect) { if (tildefriends.https_port && gGlobalSettings.http_redirect) {
httpd.set_http_redirect(settings.http_redirect); httpd.set_http_redirect(gGlobalSettings.http_redirect);
} }
httpd.all('/app/socket', app.socket); httpd.all('/app/socket', app.socket);
httpd.all('', function default_http_handler(request, response) { httpd.all('', function default_http_handler(request, response) {
@ -1232,4 +1312,43 @@ loadSettings()
exit(1); exit(1);
}); });
export {invoke, getProcessBlob}; /**
* TODOC
* @param {*} user
* @param {*} packageOwner
* @param {*} packageName
* @param {*} permission
* @param {*} allow
*/
function storePermission(user, packageOwner, packageName, permission, allow) {
if (!gGlobalSettings.userPermissions) {
gGlobalSettings.userPermissions = {};
}
if (!gGlobalSettings.userPermissions[user]) {
gGlobalSettings.userPermissions[user] = {};
}
if (!gGlobalSettings.userPermissions[user][packageOwner]) {
gGlobalSettings.userPermissions[user][packageOwner] = {};
}
if (!gGlobalSettings.userPermissions[user][packageOwner][packageName]) {
gGlobalSettings.userPermissions[user][packageOwner][packageName] = {};
}
if (
gGlobalSettings.userPermissions[user][packageOwner][packageName][
permission
] !== allow
) {
if (allow === undefined) {
delete gGlobalSettings.userPermissions[user][packageOwner][packageName][
permission
];
} else {
gGlobalSettings.userPermissions[user][packageOwner][packageName][
permission
] = allow;
}
setGlobalSettings(gGlobalSettings);
}
}
export {gGlobalSettings as globalSettings, invoke, getSessionProcessBlob};

View File

@ -21,14 +21,14 @@
}: }:
pkgs.stdenv.mkDerivation rec { pkgs.stdenv.mkDerivation rec {
pname = "tildefriends"; pname = "tildefriends";
version = "0.0.23"; version = "0.0.22";
src = pkgs.fetchFromGitea { src = pkgs.fetchFromGitea {
domain = "dev.tildefriends.net"; domain = "dev.tildefriends.net";
owner = "cory"; owner = "cory";
repo = "tildefriends"; repo = "tildefriends";
rev = "v${version}"; rev = "v${version}";
hash = "sha256-ukZpi+BXRTFGbdvd5ApmctTo8bjtPJMHjqFPgVSyBWU="; hash = "sha256-Su+y++zVXmYNbwfhCP6w5e36oxW5fkURPFzFLjbyFEI=";
fetchSubmodules = true; fetchSubmodules = true;
}; };

2
deps/c-ares vendored

@ -1 +1 @@
Subproject commit a57ff692eeab8d21c853dc1ddaf0164f517074c3 Subproject commit 27b98d96eff6122fb981e338bddef3d6a57d8d44

File diff suppressed because one or more lines are too long

224
deps/codemirror_src/package-lock.json generated vendored
View File

@ -37,9 +37,9 @@
} }
}, },
"node_modules/@codemirror/commands": { "node_modules/@codemirror/commands": {
"version": "6.7.0", "version": "6.6.2",
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.7.0.tgz", "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.6.2.tgz",
"integrity": "sha512-+cduIZ2KbesDhbykV02K25A5xIVrquSPz4UxxYBemRlAT2aW8dhwUgLDwej7q/RJUHKk4nALYcR1puecDvbdqw==", "integrity": "sha512-Fq7eWOl1Rcbrfn6jD8FPCj9Auaxdm5nIK5RYOeW7ughnd/rY5AmPg6b+CfsG39ZHdwiwe8lde3q8uR7CF5S0yQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@codemirror/language": "^6.0.0", "@codemirror/language": "^6.0.0",
@ -104,9 +104,9 @@
} }
}, },
"node_modules/@codemirror/language": { "node_modules/@codemirror/language": {
"version": "6.10.3", "version": "6.10.2",
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.3.tgz", "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.2.tgz",
"integrity": "sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==", "integrity": "sha512-kgbTYTo0Au6dCSc/TFy7fK3fpJmgHDv1sG1KNQKJXVi+xBTEeBPY/M30YXiU6mMXeH+YIDLsbrT4ZwNRdtF+SA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@codemirror/state": "^6.0.0", "@codemirror/state": "^6.0.0",
@ -118,9 +118,9 @@
} }
}, },
"node_modules/@codemirror/lint": { "node_modules/@codemirror/lint": {
"version": "6.8.2", "version": "6.8.1",
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.2.tgz", "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.1.tgz",
"integrity": "sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==", "integrity": "sha512-IZ0Y7S4/bpaunwggW2jYqwLuHj0QtESf5xcROewY6+lDNwZ/NzvR4t+vpYgg9m7V8UXLPYqG+lu3DF470E5Oxg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@codemirror/state": "^6.0.0", "@codemirror/state": "^6.0.0",
@ -158,9 +158,9 @@
} }
}, },
"node_modules/@codemirror/view": { "node_modules/@codemirror/view": {
"version": "6.34.1", "version": "6.33.0",
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.1.tgz", "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.33.0.tgz",
"integrity": "sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==", "integrity": "sha512-AroaR3BvnjRW8fiZBalAaK+ZzB5usGgI014YKElYZvQdNH5ZIidHlO+cyf/2rWzyBFRkvG6VhiXeAEbC53P2YQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@codemirror/state": "^6.4.0", "@codemirror/state": "^6.4.0",
@ -233,9 +233,9 @@
} }
}, },
"node_modules/@lezer/common": { "node_modules/@lezer/common": {
"version": "1.2.2", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.2.tgz", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz",
"integrity": "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw==", "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@lezer/css": { "node_modules/@lezer/css": {
@ -270,9 +270,9 @@
} }
}, },
"node_modules/@lezer/javascript": { "node_modules/@lezer/javascript": {
"version": "1.4.19", "version": "1.4.18",
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.19.tgz", "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.18.tgz",
"integrity": "sha512-j44kbR1QL26l6dMunZ1uhKBFteVGLVCBGNUD2sUaMnic+rbTviVuoK0CD1l9FTW31EueWvFFswCKMH7Z+M3JRA==", "integrity": "sha512-Y8BeHOt4LtcxJgXwadtfSeWPrh0XzklcCHnCVT+vOsxqH4gWmunP2ykX+VVOlM/dusyVyiNfG3lv0f10UK+mgA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@lezer/common": "^1.2.0", "@lezer/common": "^1.2.0",
@ -301,14 +301,15 @@
} }
}, },
"node_modules/@rollup/plugin-node-resolve": { "node_modules/@rollup/plugin-node-resolve": {
"version": "15.3.0", "version": "15.2.3",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
"integrity": "sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==", "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@rollup/pluginutils": "^5.0.1", "@rollup/pluginutils": "^5.0.1",
"@types/resolve": "1.20.2", "@types/resolve": "1.20.2",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"is-builtin-module": "^3.2.1",
"is-module": "^1.0.0", "is-module": "^1.0.0",
"resolve": "^1.22.1" "resolve": "^1.22.1"
}, },
@ -348,9 +349,9 @@
} }
}, },
"node_modules/@rollup/pluginutils": { "node_modules/@rollup/pluginutils": {
"version": "5.1.2", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
"integrity": "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==", "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/estree": "^1.0.0", "@types/estree": "^1.0.0",
@ -370,9 +371,9 @@
} }
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.3.tgz",
"integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", "integrity": "sha512-MmKSfaB9GX+zXl6E8z4koOr/xU63AMVleLEa64v7R0QF/ZloMs5vcD1sHgM64GXXS1csaJutG+ddtzcueI/BLg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -383,9 +384,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.3.tgz",
"integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", "integrity": "sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -396,9 +397,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.3.tgz",
"integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", "integrity": "sha512-P0UxIOrKNBFTQaXTxOH4RxuEBVCgEA5UTNV6Yz7z9QHnUJ7eLX9reOd/NYMO3+XZO2cco19mXTxDMXxit4R/eQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -409,9 +410,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.3.tgz",
"integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", "integrity": "sha512-L1M0vKGO5ASKntqtsFEjTq/fD91vAqnzeaF6sfNAy55aD+Hi2pBI5DKwCO+UNDQHWsDViJLqshxOahXyLSh3EA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -422,9 +423,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.3.tgz",
"integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", "integrity": "sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -435,9 +436,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.3.tgz",
"integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", "integrity": "sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -448,9 +449,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.3.tgz",
"integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", "integrity": "sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -461,9 +462,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.3.tgz",
"integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", "integrity": "sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -474,9 +475,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.3.tgz",
"integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", "integrity": "sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -487,9 +488,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.3.tgz",
"integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", "integrity": "sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@ -500,9 +501,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.3.tgz",
"integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", "integrity": "sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@ -513,9 +514,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.3.tgz",
"integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", "integrity": "sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -526,9 +527,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.3.tgz",
"integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", "integrity": "sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -539,9 +540,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.3.tgz",
"integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", "integrity": "sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -552,9 +553,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.3.tgz",
"integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", "integrity": "sha512-nMIdKnfZfzn1Vsk+RuOvl43ONTZXoAPUUxgcU0tXooqg4YrAqzfKzVenqqk2g5efWh46/D28cKFrOzDSW28gTA==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -565,9 +566,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.3.tgz",
"integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", "integrity": "sha512-fOvu7PCQjAj4eWDEuD8Xz5gpzFqXzGlxHZozHP4b9Jxv9APtdxL6STqztDzMLuRXEc4UpXGGhx029Xgm91QBeA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -609,6 +610,18 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/builtin-modules": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
"integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
"license": "MIT",
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/codemirror": { "node_modules/codemirror": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
@ -687,6 +700,21 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/is-builtin-module": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
"integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
"license": "MIT",
"dependencies": {
"builtin-modules": "^3.3.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-core-module": { "node_modules/is-core-module": {
"version": "2.15.1", "version": "2.15.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
@ -754,12 +782,12 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.24.0", "version": "4.21.3",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.3.tgz",
"integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", "integrity": "sha512-7sqRtBNnEbcBtMeRVc6VRsJMmpI+JU1z9VTvW8D4gXIYQFz0aLcsE6rRkyghZkLfEgUZgVvOG7A5CVz/VW5GIA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/estree": "1.0.6" "@types/estree": "1.0.5"
}, },
"bin": { "bin": {
"rollup": "dist/bin/rollup" "rollup": "dist/bin/rollup"
@ -769,25 +797,31 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.24.0", "@rollup/rollup-android-arm-eabi": "4.21.3",
"@rollup/rollup-android-arm64": "4.24.0", "@rollup/rollup-android-arm64": "4.21.3",
"@rollup/rollup-darwin-arm64": "4.24.0", "@rollup/rollup-darwin-arm64": "4.21.3",
"@rollup/rollup-darwin-x64": "4.24.0", "@rollup/rollup-darwin-x64": "4.21.3",
"@rollup/rollup-linux-arm-gnueabihf": "4.24.0", "@rollup/rollup-linux-arm-gnueabihf": "4.21.3",
"@rollup/rollup-linux-arm-musleabihf": "4.24.0", "@rollup/rollup-linux-arm-musleabihf": "4.21.3",
"@rollup/rollup-linux-arm64-gnu": "4.24.0", "@rollup/rollup-linux-arm64-gnu": "4.21.3",
"@rollup/rollup-linux-arm64-musl": "4.24.0", "@rollup/rollup-linux-arm64-musl": "4.21.3",
"@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.21.3",
"@rollup/rollup-linux-riscv64-gnu": "4.24.0", "@rollup/rollup-linux-riscv64-gnu": "4.21.3",
"@rollup/rollup-linux-s390x-gnu": "4.24.0", "@rollup/rollup-linux-s390x-gnu": "4.21.3",
"@rollup/rollup-linux-x64-gnu": "4.24.0", "@rollup/rollup-linux-x64-gnu": "4.21.3",
"@rollup/rollup-linux-x64-musl": "4.24.0", "@rollup/rollup-linux-x64-musl": "4.21.3",
"@rollup/rollup-win32-arm64-msvc": "4.24.0", "@rollup/rollup-win32-arm64-msvc": "4.21.3",
"@rollup/rollup-win32-ia32-msvc": "4.24.0", "@rollup/rollup-win32-ia32-msvc": "4.21.3",
"@rollup/rollup-win32-x64-msvc": "4.24.0", "@rollup/rollup-win32-x64-msvc": "4.21.3",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"node_modules/rollup/node_modules/@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"license": "MIT"
},
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -866,9 +900,9 @@
} }
}, },
"node_modules/terser": { "node_modules/terser": {
"version": "5.34.1", "version": "5.33.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.34.1.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.33.0.tgz",
"integrity": "sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==", "integrity": "sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {

2
deps/libuv vendored

@ -1 +1 @@
Subproject commit 8be336f4ee296d20e1c071a44d6adf279e202236 Subproject commit d2e56a5e8d3e39947b78405ca6e4727c70f5568a

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
package-lock.json generated
View File

@ -11,9 +11,7 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.3.3", "version": "3.2.5",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
"license": "MIT", "license": "MIT",
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unprompted.tildefriends" package="com.unprompted.tildefriends"
android:versionCode="28" android:versionCode="27"
android:versionName="0.0.24-wip"> android:versionName="0.0.23">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<application <application

View File

@ -11,7 +11,6 @@ import android.net.ConnectivityManager;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.os.FileObserver;
import android.os.IBinder; import android.os.IBinder;
import android.os.Parcel; import android.os.Parcel;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
@ -43,6 +42,12 @@ import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileReader; import java.io.FileReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.file.FileSystems;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class TildeFriendsActivity extends Activity { public class TildeFriendsActivity extends Activity {
@ -50,9 +55,9 @@ public class TildeFriendsActivity extends Activity {
TildeFriendsWebView web_view; TildeFriendsWebView web_view;
String base_url; String base_url;
String port_file_path; String port_file_path;
Thread thread;
Thread server_thread; Thread server_thread;
ServiceConnection service_connection; ServiceConnection service_connection;
FileObserver observer;
private ValueCallback<Uri[]> upload_message; private ValueCallback<Uri[]> upload_message;
private final static int FILECHOOSER_RESULT = 1; private final static int FILECHOOSER_RESULT = 1;
@ -90,9 +95,56 @@ public class TildeFriendsActivity extends Activity {
TildeFriendsActivity activity = this; TildeFriendsActivity activity = this;
thread = new Thread(new Runnable() {
@Override
public void run() {
Log.w("tildefriends", "Watching for changes in: " + getFilesDir().toString()); Log.w("tildefriends", "Watching for changes in: " + getFilesDir().toString());
observer = make_file_observer(getFilesDir().toString(), port_file_path); try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
observer.startWatching(); Paths.get(getFilesDir().toString()).register(
watcher,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY);
while (true) {
WatchKey key = watcher.poll(100, TimeUnit.MILLISECONDS);
boolean attempt_it = true;
if (key != null)
{
attempt_it = false;
for (WatchEvent event : key.pollEvents()) {
if (event.context().toString().equals("port.txt")) {
Log.w("tildefriends", "Observed file write: " + event.context().toString());
attempt_it = true;
}
}
}
if (attempt_it) {
int port = read_port(port_file_path);
if (port >= 0) {
base_url = "http://127.0.0.1:" + String.valueOf(port) + "/";
activity.runOnUiThread(() -> {
activity.hide_status();
web_view.loadUrl(base_url);
});
break;
} else {
activity.runOnUiThread(() -> {
activity.set_status("Waiting to connect...");
});
}
}
if (key != null && !key.reset()) {
Log.w("tildefriends", "watcher is no longer valid");
break;
}
}
} catch (java.io.IOException e) {
Log.w("tildefriends", "IOException: " + e.toString());
} catch (InterruptedException e) {
Log.w("tildefriends", "InterruptedException: " + e.toString());
}
}
});
thread.start();
set_status("Starting server..."); set_status("Starting server...");
server_thread = new Thread(new Runnable() { server_thread = new Thread(new Runnable() {
@ -340,14 +392,11 @@ public class TildeFriendsActivity extends Activity {
private int read_port(String path) { private int read_port(String path) {
try (BufferedReader reader = new BufferedReader(new FileReader(path))) { try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
String line = reader.readLine(); return Integer.parseInt(reader.readLine());
if (line != null) {
return Integer.parseInt(line);
}
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
e.printStackTrace(); e.printStackTrace();
} catch (java.io.FileNotFoundException e) { } catch (java.io.FileNotFoundException e) {
Log.w("tildefriends", "Port file does not yet exist."); e.printStackTrace();
} catch (java.io.IOException e) { } catch (java.io.IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -412,36 +461,6 @@ public class TildeFriendsActivity extends Activity {
} }
} }
private void check_port_file(String path) {
int port = read_port(port_file_path);
if (port >= 0) {
base_url = "http://127.0.0.1:" + String.valueOf(port) + "/";
runOnUiThread(() -> {
hide_status();
web_view.loadUrl(base_url);
});
observer = null;
} else {
runOnUiThread(() -> {
set_status("Waiting to connect...");
});
}
}
@SuppressWarnings("deprecation")
private FileObserver make_file_observer(String dir, String path) {
FileObserver file_observer = new FileObserver(dir, FileObserver.ALL_EVENTS) {
@Override
public void onEvent(int event, String file) {
if (observer != null) {
check_port_file(path);
}
}
};
check_port_file(path);
return file_observer;
}
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private void set_database_path() private void set_database_path()
{ {

View File

@ -41,7 +41,7 @@ public class TildeFriendsSandboxService extends Service {
@Override @Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) { protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
if (code == START_CALL) { if (code == START_CALL) {
ParcelFileDescriptor pfd = read_pfd(data); ParcelFileDescriptor pfd = data.readParcelable(ParcelFileDescriptor.class.getClassLoader(), ParcelFileDescriptor.class);
if (pfd != null) { if (pfd != null) {
Log.w("tildefriends", "fd is " + pfd.getFd()); Log.w("tildefriends", "fd is " + pfd.getFd());
start_thread(pfd.detachFd()); start_thread(pfd.detachFd());
@ -56,9 +56,4 @@ public class TildeFriendsSandboxService extends Service {
} }
}; };
} }
@SuppressWarnings("deprecation")
static private ParcelFileDescriptor read_pfd(Parcel data) {
return data.readParcelable(ParcelFileDescriptor.class.getClassLoader());
}
} }

View File

@ -4,8 +4,8 @@
#include "http.h" #include "http.h"
#include "log.h" #include "log.h"
#include "mem.h" #include "mem.h"
#include "ssb.db.h"
#include "ssb.h" #include "ssb.h"
#include "ssb.db.h"
#include "task.h" #include "task.h"
#include "tlscontext.js.h" #include "tlscontext.js.h"
#include "trace.h" #include "trace.h"
@ -41,8 +41,6 @@ static JSValue _authenticate_jwt(tf_ssb_t* ssb, JSContext* context, const char*
static JSValue _httpd_websocket_upgrade(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _httpd_websocket_upgrade(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static const char* _make_session_jwt(JSContext* context, tf_ssb_t* ssb, const char* name); static const char* _make_session_jwt(JSContext* context, tf_ssb_t* ssb, const char* name);
static const char* _make_set_session_cookie_header(tf_http_request_t* request, const char* session_cookie); static const char* _make_set_session_cookie_header(tf_http_request_t* request, const char* session_cookie);
const char** _form_data_decode(const char* data, int length);
const char* _form_data_get(const char** form_data, const char* key);
static JSClassID _httpd_class_id; static JSClassID _httpd_class_id;
static JSClassID _httpd_request_class_id; static JSClassID _httpd_request_class_id;
@ -557,11 +555,14 @@ static bool _magic_bytes_match(const magic_bytes_t* magic, const uint8_t* actual
return true; return true;
} }
static const char* _httpd_mime_type_from_magic_bytes_internal(const uint8_t* bytes, size_t size) static JSValue _httpd_mime_type_from_magic_bytes(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{ {
const char* type = "application/binary"; JSValue result = JS_UNDEFINED;
size_t size = 0;
uint8_t* bytes = tf_util_try_get_array_buffer(context, &size, argv[0]);
if (bytes) if (bytes)
{ {
const magic_bytes_t k_magic_bytes[] = { const magic_bytes_t k_magic_bytes[] = {
{ {
.type = "image/jpeg", .type = "image/jpeg",
@ -626,19 +627,12 @@ static const char* _httpd_mime_type_from_magic_bytes_internal(const uint8_t* byt
{ {
if (_magic_bytes_match(&k_magic_bytes[i], bytes, size)) if (_magic_bytes_match(&k_magic_bytes[i], bytes, size))
{ {
type = k_magic_bytes[i].type; result = JS_NewString(context, k_magic_bytes[i].type);
break; break;
} }
} }
} }
return type; return result;
}
static JSValue _httpd_mime_type_from_magic_bytes(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
size_t size = 0;
uint8_t* bytes = tf_util_try_get_array_buffer(context, &size, argv[0]);
return JS_NewString(context, _httpd_mime_type_from_magic_bytes_internal(bytes, size));
} }
static const char* _ext_to_content_type(const char* ext, bool use_fallback) static const char* _ext_to_content_type(const char* ext, bool use_fallback)
@ -965,124 +959,6 @@ static void _httpd_endpoint_static(tf_http_request_t* request)
tf_file_stat(task, path, _httpd_endpoint_static_stat, request); tf_file_stat(task, path, _httpd_endpoint_static_stat, request);
} }
typedef struct _view_t
{
tf_http_request_t* request;
const char** form_data;
void* data;
size_t size;
bool not_modified;
} view_t;
static bool _is_filename_safe(const char* filename)
{
if (!filename)
{
return NULL;
}
for (const char* p = filename; *p; p++)
{
if ((*p <= 'a' && *p >= 'z') &&
(*p <= 'A' && *p >= 'Z') &&
(*p <= '0' && *p >= '9') &&
*p != '.' &&
*p != '-' &&
*p != '_')
{
return false;
}
}
return strlen(filename) < 256;
}
static void _httpd_endpoint_view_work(tf_ssb_t* ssb, void* user_data)
{
view_t* view = user_data;
tf_http_request_t* request = view->request;
char blob_id[256] = "";
if (request->path[0] == '/' && request->path[1] == '~')
{
char user[256] = "";
char path[1024] = "";
const char* slash = strchr(request->path + 2, '/');
if (slash)
{
snprintf(user, sizeof(user), "%.*s", (int)(slash - (request->path + 2)), request->path + 2);
snprintf(path, sizeof(path), "path:%.*s", (int)(strlen(slash + 1) - strlen("/view")), slash + 1);
const char* value = tf_ssb_db_get_property(ssb, user, path);
snprintf(blob_id, sizeof(blob_id), "%s", value);
tf_free((void*)value);
}
}
else if (request->path[0] == '/' && request->path[1] == '&')
{
snprintf(blob_id, sizeof(blob_id), "%.*s", (int)(strlen(request->path) - strlen("/view") - 1), request->path + 1);
}
if (*blob_id)
{
const char* if_none_match = tf_http_request_get_header(request, "if-none-match");
char match[258];
snprintf(match, sizeof(match), "\"%s\"", blob_id);
if (if_none_match && strcmp(if_none_match, match))
{
view->not_modified = true;
}
else
{
tf_ssb_db_blob_get(ssb, blob_id, (uint8_t**)&view->data, &view->size);
}
}
}
static void _httpd_endpoint_view_after_work(tf_ssb_t* ssb, int status, void* user_data)
{
view_t* view = user_data;
const char* filename = _form_data_get(view->form_data, "filename");
if (!_is_filename_safe(filename))
{
filename = NULL;
}
char content_disposition[512] = "";
if (filename)
{
snprintf(content_disposition, sizeof(content_disposition), "attachment; filename=%s", filename);
}
const char* headers[] = {
"Content-Security-Policy", "sandbox allow-downloads allow-top-navigation-by-user-activation",
"Content-Type", view->data ? _httpd_mime_type_from_magic_bytes_internal(view->data, view->size) : "text/plain",
filename ? "Content-Disposition" : NULL, filename ? content_disposition : NULL,
};
int count = filename ? tf_countof(headers) / 2 : (tf_countof(headers) / 2 - 1);
if (view->not_modified)
{
tf_http_respond(view->request, 304, headers, count, NULL, 0);
}
else if (view->data)
{
tf_http_respond(view->request, 200, headers, count, view->data, view->size);
tf_free(view->data);
}
else
{
const char* k_payload = tf_http_status_text(404);
tf_http_respond(view->request, 404, NULL, 0, k_payload, strlen(k_payload));
}
tf_free(view->form_data);
tf_http_request_unref(view->request);
tf_free(view);
}
static void _httpd_endpoint_view(tf_http_request_t* request)
{
tf_http_request_ref(request);
tf_task_t* task = request->user_data;
tf_ssb_t* ssb = tf_task_get_ssb(task);
view_t* view = tf_malloc(sizeof(view_t));
*view = (view_t) { .request = request, .form_data = _form_data_decode(request->query, request->query ? strlen(request->query) : 0) };
tf_ssb_run_work(ssb, _httpd_endpoint_view_work, _httpd_endpoint_view_after_work, view);
}
static void _httpd_endpoint_root_callback(const char* path, void* user_data) static void _httpd_endpoint_root_callback(const char* path, void* user_data)
{ {
tf_http_request_t* request = user_data; tf_http_request_t* request = user_data;
@ -1814,7 +1690,6 @@ void tf_httpd_register(JSContext* context)
tf_http_add_handler(http, "/.well-known/*", _httpd_endpoint_static, NULL, task); tf_http_add_handler(http, "/.well-known/*", _httpd_endpoint_static, NULL, task);
tf_http_add_handler(http, "/~*/*/", _httpd_endpoint_static, NULL, task); tf_http_add_handler(http, "/~*/*/", _httpd_endpoint_static, NULL, task);
tf_http_add_handler(http, "/&*.sha256/", _httpd_endpoint_static, NULL, task); tf_http_add_handler(http, "/&*.sha256/", _httpd_endpoint_static, NULL, task);
tf_http_add_handler(http, "/*/view", _httpd_endpoint_view, NULL, task);
tf_http_add_handler(http, "/robots.txt", _httpd_endpoint_robots_txt, NULL, NULL); tf_http_add_handler(http, "/robots.txt", _httpd_endpoint_robots_txt, NULL, NULL);
tf_http_add_handler(http, "/debug", _httpd_endpoint_debug, NULL, task); tf_http_add_handler(http, "/debug", _httpd_endpoint_debug, NULL, task);

Binary file not shown.

View File

@ -2,14 +2,15 @@
#include "util.js.h" #include "util.js.h"
#include "uv.h"
#include "quickjs.h" #include "quickjs.h"
#include "sqlite3.h" #include "sqlite3.h"
#include "uv.h" #include "uv.h"
#include <openssl/crypto.h> #include <openssl/crypto.h>
#include <stdbool.h>
#include <string.h> #include <string.h>
#include <stdbool.h>
typedef struct _tf_mem_node_t tf_mem_node_t; typedef struct _tf_mem_node_t tf_mem_node_t;

View File

@ -6,9 +6,9 @@
#include "trace.h" #include "trace.h"
#include "util.js.h" #include "util.js.h"
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <assert.h> #include <assert.h>

269
src/ssb.c
View File

@ -81,7 +81,6 @@ enum
k_seed_check_interval_seconds = 5 * 60, k_seed_check_interval_seconds = 5 * 60,
k_udp_discovery_expires_seconds = 10, k_udp_discovery_expires_seconds = 10,
k_handshake_timeout_ms = 15000, k_handshake_timeout_ms = 15000,
k_rpc_active_ms = 3000,
}; };
typedef struct _tf_ssb_broadcast_t tf_ssb_broadcast_t; typedef struct _tf_ssb_broadcast_t tf_ssb_broadcast_t;
@ -113,7 +112,6 @@ typedef struct _tf_ssb_request_t
tf_ssb_callback_cleanup_t* cleanup; tf_ssb_callback_cleanup_t* cleanup;
void* user_data; void* user_data;
tf_ssb_connection_t* dependent_connection; tf_ssb_connection_t* dependent_connection;
uint64_t last_active;
int32_t request_number; int32_t request_number;
} tf_ssb_request_t; } tf_ssb_request_t;
@ -133,7 +131,8 @@ typedef struct _tf_ssb_broadcast_t
typedef struct _tf_ssb_rpc_callback_node_t tf_ssb_rpc_callback_node_t; typedef struct _tf_ssb_rpc_callback_node_t tf_ssb_rpc_callback_node_t;
typedef struct _tf_ssb_rpc_callback_node_t typedef struct _tf_ssb_rpc_callback_node_t
{ {
const char* name; const char** name;
const char* flattened_name;
tf_ssb_rpc_callback_t* callback; tf_ssb_rpc_callback_t* callback;
tf_ssb_callback_cleanup_t* cleanup; tf_ssb_callback_cleanup_t* cleanup;
void* user_data; void* user_data;
@ -213,7 +212,6 @@ typedef struct _tf_ssb_t
uv_timer_t broadcast_cleanup_timer; uv_timer_t broadcast_cleanup_timer;
uv_timer_t broadcast_timer; uv_timer_t broadcast_timer;
uv_timer_t trace_timer; uv_timer_t trace_timer;
uv_timer_t request_activity_timer;
uv_tcp_t server; uv_tcp_t server;
uint8_t network_key[32]; uint8_t network_key[32];
@ -363,10 +361,6 @@ typedef struct _tf_ssb_connection_t
int read_back_pressure; int read_back_pressure;
int active_write_count; int active_write_count;
uint64_t last_notified_active;
int flags;
} tf_ssb_connection_t; } tf_ssb_connection_t;
static JSClassID _connection_class_id; static JSClassID _connection_class_id;
@ -664,40 +658,6 @@ static int _request_compare(const void* a, const void* b)
return ai < br->request_number ? -1 : br->request_number < ai ? 1 : 0; return ai < br->request_number ? -1 : br->request_number < ai ? 1 : 0;
} }
static void _tf_ssb_request_activity_timer(uv_timer_t* timer)
{
tf_ssb_t* ssb = timer->data;
uint64_t now_ms = uv_now(ssb->loop);
bool any_still_active = false;
for (tf_ssb_connection_t* connection = ssb->connections; connection; connection = connection->next)
{
bool any_changed = false;
bool last_notified_active = (now_ms - connection->last_notified_active) < k_rpc_active_ms;
for (int i = 0; i < connection->requests_count; i++)
{
bool last_active = (now_ms - connection->requests[i].last_active) < k_rpc_active_ms;
if (last_active != last_notified_active)
{
any_changed = true;
}
if (last_active)
{
any_still_active = true;
}
}
if (any_changed)
{
_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_update, connection);
connection->last_notified_active = now_ms;
}
}
if (any_still_active && uv_timer_get_due_in(&ssb->request_activity_timer) == 0)
{
uv_timer_start(&ssb->request_activity_timer, _tf_ssb_request_activity_timer, k_rpc_active_ms, 0);
}
}
static bool _tf_ssb_connection_get_request_callback(tf_ssb_connection_t* connection, int32_t request_number, tf_ssb_rpc_callback_t** out_callback, void** out_user_data) static bool _tf_ssb_connection_get_request_callback(tf_ssb_connection_t* connection, int32_t request_number, tf_ssb_rpc_callback_t** out_callback, void** out_user_data)
{ {
if (!connection->requests) if (!connection->requests)
@ -715,11 +675,6 @@ static bool _tf_ssb_connection_get_request_callback(tf_ssb_connection_t* connect
{ {
*out_user_data = request->user_data; *out_user_data = request->user_data;
} }
request->last_active = uv_now(connection->ssb->loop);
if (uv_timer_get_due_in(&connection->ssb->request_activity_timer) == 0)
{
uv_timer_start(&connection->ssb->request_activity_timer, _tf_ssb_request_activity_timer, k_rpc_active_ms, 0);
}
return true; return true;
} }
return false; return false;
@ -730,14 +685,12 @@ void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t requ
{ {
tf_ssb_request_t* existing = tf_ssb_request_t* existing =
connection->requests_count ? bsearch(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare) : NULL; connection->requests_count ? bsearch(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare) : NULL;
uint64_t now_ms = uv_now(connection->ssb->loop);
if (existing) if (existing)
{ {
assert(!existing->callback); assert(!existing->callback);
assert(!existing->cleanup); assert(!existing->cleanup);
assert(!existing->user_data); assert(!existing->user_data);
assert(!existing->dependent_connection); assert(!existing->dependent_connection);
existing->last_active = now_ms;
existing->callback = callback; existing->callback = callback;
existing->cleanup = cleanup; existing->cleanup = cleanup;
existing->user_data = user_data; existing->user_data = user_data;
@ -752,7 +705,6 @@ void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t requ
.cleanup = cleanup, .cleanup = cleanup,
.user_data = user_data, .user_data = user_data,
.dependent_connection = dependent_connection, .dependent_connection = dependent_connection,
.last_active = now_ms,
}; };
snprintf(request.name, sizeof(request.name), "%s", name); snprintf(request.name, sizeof(request.name), "%s", name);
int index = tf_util_insert_index(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare); int index = tf_util_insert_index(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare);
@ -763,14 +715,10 @@ void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t requ
} }
connection->requests[index] = request; connection->requests[index] = request;
connection->requests_count++; connection->requests_count++;
connection->ssb->request_count++; connection->ssb->request_count++;
} }
if (uv_timer_get_due_in(&connection->ssb->request_activity_timer) == 0)
{
uv_timer_start(&connection->ssb->request_activity_timer, _tf_ssb_request_activity_timer, k_rpc_active_ms, 0);
}
_tf_ssb_notify_connections_changed(connection->ssb, k_tf_ssb_change_update, connection); _tf_ssb_notify_connections_changed(connection->ssb, k_tf_ssb_change_update, connection);
connection->last_notified_active = now_ms;
} }
static int _message_request_compare(const void* a, const void* b) static int _message_request_compare(const void* a, const void* b)
@ -1150,11 +1098,11 @@ bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* ou
return false; return false;
} }
void tf_ssb_close_all(tf_ssb_t* ssb, const char* reason) void tf_ssb_close_all(tf_ssb_t* ssb)
{ {
for (tf_ssb_connection_t* connection = ssb->connections; connection; connection = connection->next) for (tf_ssb_connection_t* connection = ssb->connections; connection; connection = connection->next)
{ {
_tf_ssb_connection_close(connection, reason); _tf_ssb_connection_close(connection, "tf_ssb_close_all");
} }
} }
@ -1573,28 +1521,60 @@ static bool _tf_ssb_connection_recv_pop(tf_ssb_connection_t* connection, uint8_t
return true; return true;
} }
static void _tf_ssb_name_to_string(JSContext* context, JSValue object, char* buffer, size_t size) static bool _tf_ssb_name_equals(JSContext* context, JSValue object, const char** match)
{ {
bool result = true;
JSValue name = JS_GetPropertyStr(context, object, "name"); JSValue name = JS_GetPropertyStr(context, object, "name");
if (JS_IsArray(context, name)) if (JS_IsArray(context, name))
{ {
int length = tf_util_get_length(context, name); int length = tf_util_get_length(context, name);
int offset = 0;
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {
JSValue part = JS_GetPropertyUint32(context, name, i); if (!match[i])
const char* part_str = JS_ToCString(context, part); {
offset += snprintf(buffer + offset, size - offset, "%s%s", i == 0 ? "" : ".", part_str); result = false;
JS_FreeCString(context, part_str); break;
JS_FreeValue(context, part); }
JSValue element = JS_GetPropertyUint32(context, name, i);
const char* str = JS_ToCString(context, element);
if (!str || strcmp(str, match[i]) != 0)
{
result = false;
}
JS_FreeCString(context, str);
JS_FreeValue(context, element);
}
if (result && match[length])
{
result = false;
} }
} }
else if (JS_IsString(name)) else if (JS_IsString(name))
{ {
const char* part_str = JS_ToCString(context, name); /* Manifest is traditionally sent as not an array for some reason. */
snprintf(buffer, size, "%s", part_str); const char* str = JS_ToCString(context, name);
JS_FreeCString(context, part_str); result = str && match[0] && strcmp(str, match[0]) == 0 && !match[1];
JS_FreeCString(context, str);
} }
else
{
result = false;
}
JS_FreeValue(context, name);
return result;
}
static void _tf_ssb_name_to_string(JSContext* context, JSValue object, char* buffer, size_t size)
{
JSValue name = JS_GetPropertyStr(context, object, "name");
JSValue json_val = JS_JSONStringify(context, name, JS_NULL, JS_NewInt32(context, 2));
const char* value = JS_ToCString(context, json_val);
snprintf(buffer, size, "%s", value);
JS_FreeCString(context, value);
JS_FreeValue(context, json_val);
JS_FreeValue(context, name); JS_FreeValue(context, name);
} }
@ -1644,14 +1624,35 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
else if (JS_IsObject(val)) else if (JS_IsObject(val))
{ {
bool found = false; bool found = false;
char name[256] = ""; char namebuf[256] = "";
_tf_ssb_name_to_string(context, val, name, sizeof(name)); JSValue name = JS_GetPropertyStr(context, val, "name");
if (JS_IsArray(context, name))
{
int length = tf_util_get_length(context, name);
int offset = 0;
for (int i = 0; i < length; i++)
{
JSValue part = JS_GetPropertyUint32(context, name, i);
const char* part_str = JS_ToCString(context, part);
offset += snprintf(namebuf + offset, sizeof(namebuf) - offset, "%s%s", i == 0 ? "" : ".", part_str);
JS_FreeCString(context, part_str);
JS_FreeValue(context, part);
}
}
else if (JS_IsString(name))
{
const char* part_str = JS_ToCString(context, name);
snprintf(namebuf, sizeof(namebuf), "%s", part_str);
JS_FreeCString(context, part_str);
}
JS_FreeValue(context, name);
for (tf_ssb_rpc_callback_node_t* it = connection->ssb->rpc; it; it = it->next) for (tf_ssb_rpc_callback_node_t* it = connection->ssb->rpc; it; it = it->next)
{ {
if (strcmp(name, it->name) == 0) if (_tf_ssb_name_equals(context, val, it->name))
{ {
tf_ssb_connection_add_request(connection, -request_number, name, NULL, NULL, NULL, NULL); tf_ssb_connection_add_request(connection, -request_number, namebuf, NULL, NULL, NULL, NULL);
tf_trace_begin(connection->ssb->trace, it->name); tf_trace_begin(connection->ssb->trace, it->flattened_name);
PRE_CALLBACK(connection->ssb, it->callback); PRE_CALLBACK(connection->ssb, it->callback);
it->callback(connection, flags, request_number, val, message, size, it->user_data); it->callback(connection, flags, request_number, val, message, size, it->user_data);
POST_CALLBACK(connection->ssb, it->callback); POST_CALLBACK(connection->ssb, it->callback);
@ -1660,10 +1661,12 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
break; break;
} }
} }
if (!found && strcmp(name, "Error") != 0) if (!found && !_tf_ssb_name_equals(context, val, (const char*[]) { "Error", NULL }))
{ {
tf_ssb_connection_add_request(connection, -request_number, name, NULL, NULL, NULL, NULL); tf_ssb_connection_add_request(connection, -request_number, namebuf, NULL, NULL, NULL, NULL);
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, name); char buffer[256];
_tf_ssb_name_to_string(context, val, buffer, sizeof(buffer));
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, buffer);
} }
} }
} }
@ -2269,11 +2272,6 @@ tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, const char* db_path
uv_timer_start(&ssb->trace_timer, _tf_ssb_trace_timer, 100, 100); uv_timer_start(&ssb->trace_timer, _tf_ssb_trace_timer, 100, 100);
uv_unref((uv_handle_t*)&ssb->trace_timer); uv_unref((uv_handle_t*)&ssb->trace_timer);
ssb->request_activity_timer.data = ssb;
uv_timer_init(ssb->loop, &ssb->request_activity_timer);
uv_timer_start(&ssb->request_activity_timer, _tf_ssb_request_activity_timer, k_rpc_active_ms, 0);
uv_unref((uv_handle_t*)&ssb->request_activity_timer);
if (!_tf_ssb_load_keys(ssb)) if (!_tf_ssb_load_keys(ssb))
{ {
tf_printf("Generating a new keypair.\n"); tf_printf("Generating a new keypair.\n");
@ -2476,11 +2474,6 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
uv_close((uv_handle_t*)&ssb->trace_timer, _tf_ssb_on_handle_close); uv_close((uv_handle_t*)&ssb->trace_timer, _tf_ssb_on_handle_close);
} }
if (ssb->request_activity_timer.data && !uv_is_closing((uv_handle_t*)&ssb->request_activity_timer))
{
uv_close((uv_handle_t*)&ssb->request_activity_timer, _tf_ssb_on_handle_close);
}
if (ssb->server.data && !uv_is_closing((uv_handle_t*)&ssb->server)) if (ssb->server.data && !uv_is_closing((uv_handle_t*)&ssb->server))
{ {
uv_close((uv_handle_t*)&ssb->server, _tf_ssb_on_handle_close); uv_close((uv_handle_t*)&ssb->server, _tf_ssb_on_handle_close);
@ -2497,7 +2490,7 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
tf_printf("Waiting for closes.\n"); tf_printf("Waiting for closes.\n");
while (ssb->broadcast_listener.data || ssb->broadcast_sender.data || ssb->broadcast_timer.data || ssb->broadcast_cleanup_timer.data || ssb->trace_timer.data || while (ssb->broadcast_listener.data || ssb->broadcast_sender.data || ssb->broadcast_timer.data || ssb->broadcast_cleanup_timer.data || ssb->trace_timer.data ||
ssb->server.data || ssb->ref_count || ssb->request_activity_timer.data) ssb->server.data || ssb->ref_count)
{ {
uv_run(ssb->loop, UV_RUN_ONCE); uv_run(ssb->loop, UV_RUN_ONCE);
} }
@ -2747,7 +2740,6 @@ static void _tf_ssb_connection_tunnel_callback(
tf_ssb_connection_t* tunnel = user_data; tf_ssb_connection_t* tunnel = user_data;
if (flags & k_ssb_rpc_flag_end_error) if (flags & k_ssb_rpc_flag_end_error)
{ {
tf_ssb_connection_remove_request(connection, -request_number);
tf_ssb_connection_rpc_send(connection, flags, -request_number, NULL, (const uint8_t*)"false", strlen("false"), NULL, NULL, NULL); tf_ssb_connection_rpc_send(connection, flags, -request_number, NULL, (const uint8_t*)"false", strlen("false"), NULL, NULL, NULL);
tf_ssb_connection_close(tunnel); tf_ssb_connection_close(tunnel);
} }
@ -2757,7 +2749,7 @@ static void _tf_ssb_connection_tunnel_callback(
} }
} }
tf_ssb_connection_t* tf_ssb_connection_tunnel_create(tf_ssb_t* ssb, const char* portal_id, int32_t request_number, const char* target_id, int connect_flags) tf_ssb_connection_t* tf_ssb_connection_tunnel_create(tf_ssb_t* ssb, const char* portal_id, int32_t request_number, const char* target_id)
{ {
tf_ssb_connection_t* connection = tf_ssb_connection_get(ssb, portal_id); tf_ssb_connection_t* connection = tf_ssb_connection_get(ssb, portal_id);
@ -2767,7 +2759,6 @@ tf_ssb_connection_t* tf_ssb_connection_tunnel_create(tf_ssb_t* ssb, const char*
memset(tunnel, 0, sizeof(*tunnel)); memset(tunnel, 0, sizeof(*tunnel));
snprintf(tunnel->name, sizeof(tunnel->name), "tun%d", s_tunnel_index++); snprintf(tunnel->name, sizeof(tunnel->name), "tun%d", s_tunnel_index++);
tunnel->ssb = ssb; tunnel->ssb = ssb;
tunnel->flags = connect_flags;
tunnel->tunnel_connection = connection; tunnel->tunnel_connection = connection;
tunnel->tunnel_request_number = -request_number; tunnel->tunnel_request_number = -request_number;
tunnel->send_request_number = 1; tunnel->send_request_number = 1;
@ -2810,7 +2801,6 @@ typedef struct _connect_t
uv_getaddrinfo_t req; uv_getaddrinfo_t req;
char host[256]; char host[256];
int port; int port;
int flags;
uint8_t key[k_id_bin_len]; uint8_t key[k_id_bin_len];
} connect_t; } connect_t;
@ -2823,11 +2813,7 @@ static void _tf_on_connect_getaddrinfo(uv_getaddrinfo_t* addrinfo, int result, s
{ {
struct sockaddr_in addr = *(struct sockaddr_in*)info->ai_addr; struct sockaddr_in addr = *(struct sockaddr_in*)info->ai_addr;
addr.sin_port = htons(connect->port); addr.sin_port = htons(connect->port);
tf_ssb_connection_t* connection = tf_ssb_connection_create(connect->ssb, connect->host, &addr, connect->key); tf_ssb_connection_create(connect->ssb, connect->host, &addr, connect->key);
if (connection)
{
connection->flags = connect->flags;
}
} }
else else
{ {
@ -2839,7 +2825,7 @@ static void _tf_on_connect_getaddrinfo(uv_getaddrinfo_t* addrinfo, int result, s
tf_free(connect); tf_free(connect);
} }
void tf_ssb_connect(tf_ssb_t* ssb, const char* host, int port, const uint8_t* key, int connect_flags) void tf_ssb_connect(tf_ssb_t* ssb, const char* host, int port, const uint8_t* key)
{ {
if (ssb->shutting_down) if (ssb->shutting_down)
{ {
@ -2849,7 +2835,6 @@ void tf_ssb_connect(tf_ssb_t* ssb, const char* host, int port, const uint8_t* ke
*connect = (connect_t) { *connect = (connect_t) {
.ssb = ssb, .ssb = ssb,
.port = port, .port = port,
.flags = connect_flags,
.req.data = connect, .req.data = connect,
}; };
char id[k_id_base64_len] = { 0 }; char id[k_id_base64_len] = { 0 };
@ -2861,7 +2846,7 @@ void tf_ssb_connect(tf_ssb_t* ssb, const char* host, int port, const uint8_t* ke
int r = uv_getaddrinfo(ssb->loop, &connect->req, _tf_on_connect_getaddrinfo, host, NULL, &(struct addrinfo) { .ai_family = AF_INET }); int r = uv_getaddrinfo(ssb->loop, &connect->req, _tf_on_connect_getaddrinfo, host, NULL, &(struct addrinfo) { .ai_family = AF_INET });
if (r < 0) if (r < 0)
{ {
tf_printf("uv_getaddrinfo(%s): %s\n", host, uv_strerror(r)); tf_printf("uv_getaddrinfo: %s\n", uv_strerror(r));
tf_free(connect); tf_free(connect);
tf_ssb_unref(ssb); tf_ssb_unref(ssb);
} }
@ -3140,12 +3125,12 @@ static bool _tf_ssb_parse_broadcast(const char* in_broadcast, tf_ssb_broadcast_t
return false; return false;
} }
void tf_ssb_connect_str(tf_ssb_t* ssb, const char* address, int connect_flags) void tf_ssb_connect_str(tf_ssb_t* ssb, const char* address)
{ {
tf_ssb_broadcast_t broadcast = { 0 }; tf_ssb_broadcast_t broadcast = { 0 };
if (_tf_ssb_parse_broadcast(address, &broadcast)) if (_tf_ssb_parse_broadcast(address, &broadcast))
{ {
tf_ssb_connect(ssb, broadcast.host, ntohs(broadcast.addr.sin_port), broadcast.pub, connect_flags); tf_ssb_connect(ssb, broadcast.host, ntohs(broadcast.addr.sin_port), broadcast.pub);
} }
else else
{ {
@ -3367,6 +3352,11 @@ tf_ssb_connection_t* tf_ssb_connection_get(tf_ssb_t* ssb, const char* id)
tf_ssb_id_str_to_bin(pub, id); tf_ssb_id_str_to_bin(pub, id);
for (tf_ssb_connection_t* connection = ssb->connections; connection; connection = connection->next) for (tf_ssb_connection_t* connection = ssb->connections; connection; connection = connection->next)
{ {
if (connection->tunnel_connection)
{
continue;
}
if (memcmp(connection->serverpub, pub, k_id_bin_len) == 0) if (memcmp(connection->serverpub, pub, k_id_bin_len) == 0)
{ {
return connection; return connection;
@ -3489,18 +3479,47 @@ void tf_ssb_remove_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_connection
} }
} }
void tf_ssb_add_rpc_callback(tf_ssb_t* ssb, const char* name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data) void tf_ssb_add_rpc_callback(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
{ {
size_t name_len = strlen(name); size_t name_len = 0;
tf_ssb_rpc_callback_node_t* node = tf_malloc(sizeof(tf_ssb_rpc_callback_node_t) + name_len + 1); int name_count = 0;
for (int i = 0; name[i]; i++)
{
name_count++;
name_len += strlen(name[i]) + 1;
}
tf_ssb_rpc_callback_node_t* node = tf_malloc(sizeof(tf_ssb_rpc_callback_node_t) + (name_count + 1) * sizeof(const char*) + name_len + name_len + 3);
*node = (tf_ssb_rpc_callback_node_t) { *node = (tf_ssb_rpc_callback_node_t) {
.name = (const char*)(node + 1), .name = (const char**)(node + 1),
.flattened_name = (const char*)(node + 1) + (name_count + 1) * sizeof(const char*) + name_len,
.callback = callback, .callback = callback,
.cleanup = cleanup, .cleanup = cleanup,
.user_data = user_data, .user_data = user_data,
.next = ssb->rpc, .next = ssb->rpc,
}; };
memcpy((char*)node->name, name, name_len + 1); char* p = (char*)(node + 1) + (name_count + 1) * sizeof(const char*);
for (int i = 0; i < name_count; i++)
{
size_t len = strlen(name[i]);
memcpy(p, name[i], len + 1);
node->name[i] = p;
p += len + 1;
}
char* flattened_name = (char*)node->flattened_name;
for (int i = 0; i < name_count; i++)
{
size_t length = strlen(name[i]);
memcpy(flattened_name, name[i], length);
flattened_name += length;
if (i != name_count - 1)
{
*flattened_name++ = '.';
}
}
*flattened_name++ = '(';
*flattened_name++ = ')';
*flattened_name++ = '\0';
node->name[name_count] = NULL;
ssb->rpc = node; ssb->rpc = node;
ssb->rpc_count++; ssb->rpc_count++;
} }
@ -4246,13 +4265,11 @@ JSValue tf_ssb_connection_requests_to_object(tf_ssb_connection_t* connection)
{ {
JSContext* context = connection->ssb->context; JSContext* context = connection->ssb->context;
JSValue object = JS_NewArray(context); JSValue object = JS_NewArray(context);
uint64_t now_ms = uv_now(connection->ssb->loop);
for (int i = 0; i < connection->requests_count; i++) for (int i = 0; i < connection->requests_count; i++)
{ {
JSValue request = JS_NewObject(context); JSValue request = JS_NewObject(context);
JS_SetPropertyStr(context, request, "name", JS_NewString(context, connection->requests[i].name)); JS_SetPropertyStr(context, request, "name", JS_NewString(context, connection->requests[i].name));
JS_SetPropertyStr(context, request, "request_number", JS_NewInt32(context, connection->requests[i].request_number)); JS_SetPropertyStr(context, request, "request_number", JS_NewInt32(context, connection->requests[i].request_number));
JS_SetPropertyStr(context, request, "active", JS_NewBool(context, (now_ms - connection->requests[i].last_active) < k_rpc_active_ms));
JS_SetPropertyUint32(context, object, i, request); JS_SetPropertyUint32(context, object, i, request);
} }
return object; return object;
@ -4286,41 +4303,3 @@ void tf_ssb_connection_adjust_write_count(tf_ssb_connection_t* connection, int d
connection->active_write_count += delta; connection->active_write_count += delta;
_tf_ssb_connection_dispatch_scheduled(connection); _tf_ssb_connection_dispatch_scheduled(connection);
} }
void tf_ssb_sync_start(tf_ssb_t* ssb)
{
tf_ssb_connections_sync_start(ssb->connections_tracker);
}
bool tf_ssb_tunnel_create(tf_ssb_t* ssb, const char* portal_id, const char* target_id, int connect_flags)
{
tf_ssb_connection_t* connection = tf_ssb_connection_get(ssb, portal_id);
if (connection && !tf_ssb_connection_get(ssb, target_id))
{
JSContext* context = ssb->context;
int32_t request_number = tf_ssb_connection_next_request_number(connection);
JSValue message = JS_NewObject(context);
JSValue name = JS_NewArray(context);
JS_SetPropertyUint32(context, name, 0, JS_NewString(context, "tunnel"));
JS_SetPropertyUint32(context, name, 1, JS_NewString(context, "connect"));
JS_SetPropertyStr(context, message, "name", name);
JSValue arg = JS_NewObject(context);
JS_SetPropertyStr(context, arg, "portal", JS_NewString(context, portal_id));
JS_SetPropertyStr(context, arg, "target", JS_NewString(context, target_id));
JSValue args = JS_NewArray(context);
JS_SetPropertyUint32(context, args, 0, arg);
JS_SetPropertyStr(context, message, "args", args);
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "duplex"));
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, request_number, "tunnel.connect", message, NULL, NULL, NULL);
JS_FreeValue(context, message);
tf_ssb_connection_tunnel_create(ssb, portal_id, request_number, target_id, connect_flags);
return true;
}
return false;
}
int tf_ssb_connection_get_flags(tf_ssb_connection_t* connection)
{
return connection->flags;
}

View File

@ -4,8 +4,8 @@
#include "mem.h" #include "mem.h"
#include "ssb.h" #include "ssb.h"
#include "sqlite3.h"
#include "uv.h" #include "uv.h"
#include "sqlite3.h"
#include <string.h> #include <string.h>
@ -21,11 +21,6 @@ typedef struct _tf_ssb_connections_t
static void _tf_ssb_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection, void* user_data) static void _tf_ssb_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection, void* user_data)
{ {
if (!connection)
{
return;
}
tf_ssb_connections_t* connections = user_data; tf_ssb_connections_t* connections = user_data;
switch (change) switch (change)
{ {
@ -106,7 +101,7 @@ static void _tf_ssb_connections_get_next_after_work(tf_ssb_t* ssb, int status, v
uint8_t key_bin[k_id_bin_len]; uint8_t key_bin[k_id_bin_len];
if (tf_ssb_id_str_to_bin(key_bin, next->key)) if (tf_ssb_id_str_to_bin(key_bin, next->key))
{ {
tf_ssb_connect(ssb, next->host, next->port, key_bin, 0); tf_ssb_connect(ssb, next->host, next->port, key_bin);
} }
} }
tf_free(next); tf_free(next);
@ -267,82 +262,3 @@ void tf_ssb_connections_set_succeeded(tf_ssb_connections_t* connections, const c
snprintf(update->key, sizeof(update->key), "%s", key); snprintf(update->key, sizeof(update->key), "%s", key);
_tf_ssb_connections_queue_update(connections, update); _tf_ssb_connections_queue_update(connections, update);
} }
static void _tf_ssb_connections_sync_broadcast_visit(
const char* host, const struct sockaddr_in* addr, tf_ssb_broadcast_origin_t origin, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
{
tf_ssb_t* ssb = user_data;
if (tunnel)
{
char target_id[k_id_base64_len] = { 0 };
if (tf_ssb_id_bin_to_str(target_id, sizeof(target_id), pub))
{
char portal_id[k_id_base64_len] = { 0 };
if (tf_ssb_connection_get_id(tunnel, portal_id, sizeof(portal_id)))
{
tf_ssb_tunnel_create(ssb, portal_id, target_id, k_tf_ssb_connect_flag_one_shot);
}
}
}
else
{
tf_ssb_connect(ssb, host, ntohs(addr->sin_port), pub, k_tf_ssb_connect_flag_one_shot);
}
}
typedef struct _tf_ssb_connections_get_all_work_t
{
char** connections;
int connections_count;
} tf_ssb_connections_get_all_work_t;
static void _tf_ssb_connections_get_all_work(tf_ssb_t* ssb, void* user_data)
{
tf_ssb_connections_get_all_work_t* work = user_data;
sqlite3_stmt* statement;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
if (sqlite3_prepare(db, "SELECT host, port, key FROM connections ORDER BY last_attempt", -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
const char* host = (const char*)sqlite3_column_text(statement, 0);
int port = sqlite3_column_int(statement, 1);
const char* key = (const char*)sqlite3_column_text(statement, 2);
char connection[1024] = { 0 };
snprintf(connection, sizeof(connection), "net:%s:%d~shs:%s", host, port, *key == '@' ? key + 1 : key);
char* dot = strrchr(connection, '.');
if (dot && strcmp(dot, ".ed25519") == 0)
{
*dot = '\0';
}
work->connections = tf_resize_vec(work->connections, sizeof(char*) * (work->connections_count + 1));
work->connections[work->connections_count++] = tf_strdup(connection);
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare: %s\n", sqlite3_errmsg(db));
}
tf_ssb_release_db_reader(ssb, db);
}
static void _tf_ssb_connections_get_all_after_work(tf_ssb_t* ssb, int status, void* user_data)
{
tf_ssb_connections_get_all_work_t* work = user_data;
for (int i = 0; i < work->connections_count; i++)
{
tf_ssb_connect_str(ssb, work->connections[i], k_tf_ssb_connect_flag_one_shot);
tf_free(work->connections[i]);
}
tf_free(work->connections);
tf_free(work);
}
void tf_ssb_connections_sync_start(tf_ssb_connections_t* connections)
{
tf_ssb_connections_get_all_work_t* work = tf_malloc(sizeof(tf_ssb_connections_get_all_work_t));
*work = (tf_ssb_connections_get_all_work_t) { 0 };
tf_ssb_run_work(connections->ssb, _tf_ssb_connections_get_all_work, _tf_ssb_connections_get_all_after_work, work);
tf_ssb_visit_broadcasts(connections->ssb, _tf_ssb_connections_sync_broadcast_visit, connections->ssb);
}

View File

@ -53,10 +53,4 @@ void tf_ssb_connections_set_attempted(tf_ssb_connections_t* connections, const c
*/ */
void tf_ssb_connections_set_succeeded(tf_ssb_connections_t* connections, const char* host, int port, const char* key); void tf_ssb_connections_set_succeeded(tf_ssb_connections_t* connections, const char* host, int port, const char* key);
/**
** Initiate an immediate sync.
** @param connections The connections tracker.
*/
void tf_ssb_connections_sync_start(tf_ssb_connections_t* connections);
/** @} */ /** @} */

View File

@ -69,7 +69,7 @@ static void _tf_ssb_export_scandir(uv_fs_t* req)
int r = uv_fs_unlink(tf_ssb_get_loop(export->ssb), &req, path, NULL); int r = uv_fs_unlink(tf_ssb_get_loop(export->ssb), &req, path, NULL);
if (r) if (r)
{ {
tf_printf("Failed to unlink %s: %s.\n", path, uv_strerror(r)); tf_printf("Failed to unlink %s: %s.", path, uv_strerror(r));
} }
uv_fs_req_cleanup(&req); uv_fs_req_cleanup(&req);
tf_free(path); tf_free(path);
@ -199,7 +199,7 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
int r = uv_fs_scandir(tf_ssb_get_loop(ssb), &export.req, file_path, 0, _tf_ssb_export_scandir); int r = uv_fs_scandir(tf_ssb_get_loop(ssb), &export.req, file_path, 0, _tf_ssb_export_scandir);
if (r) if (r)
{ {
tf_printf("Failed to scan directory %s: %s.\n", file_path, uv_strerror(r)); tf_printf("Failed to scan directory %s: %s.", file_path, uv_strerror(r));
} }
while (!export.done) while (!export.done)
{ {

View File

@ -65,14 +65,6 @@ typedef enum _tf_ssb_message_flags_t
k_tf_ssb_message_flag_sequence_before_author = 1, k_tf_ssb_message_flag_sequence_before_author = 1,
} tf_ssb_message_flags_t; } tf_ssb_message_flags_t;
/**
** Flags affecting an SSB connection.
*/
typedef enum _tf_ssb_connect_flags_t
{
k_tf_ssb_connect_flag_one_shot = 0x1,
} tf_ssb_connect_flags_t;
/** An SSB instance. */ /** An SSB instance. */
typedef struct _tf_ssb_t tf_ssb_t; typedef struct _tf_ssb_t tf_ssb_t;
/** An SSB connection. */ /** An SSB connection. */
@ -354,17 +346,15 @@ int tf_ssb_get_connections(tf_ssb_t* ssb, tf_ssb_connection_t** out_connections,
** @param host The host name or address. ** @param host The host name or address.
** @param port The host's SHS port. ** @param port The host's SHS port.
** @param key The host's SSB identity. ** @param key The host's SSB identity.
** @param connect_flags Flags affecting the connection.
*/ */
void tf_ssb_connect(tf_ssb_t* ssb, const char* host, int port, const uint8_t* key, int connect_flags); void tf_ssb_connect(tf_ssb_t* ssb, const char* host, int port, const uint8_t* key);
/** /**
** Establish an SHS connection with a host by string address. ** Establish an SHS connection with a host by string address.
** @param ssb The SSB instance. ** @param ssb The SSB instance.
** @param address The address. ** @param address The address.
** @param connect_flags Flags affecting the connection.
*/ */
void tf_ssb_connect_str(tf_ssb_t* ssb, const char* address, int connect_flags); void tf_ssb_connect_str(tf_ssb_t* ssb, const char* address);
/** /**
** Begin listening for SHS connections on the given port. ** Begin listening for SHS connections on the given port.
@ -390,9 +380,8 @@ void tf_ssb_server_close(tf_ssb_t* ssb);
/** /**
** Close all active SHS connections. ** Close all active SHS connections.
** @param ssb The SSB instance. ** @param ssb The SSB instance.
** @param reason Reason for the close.
*/ */
void tf_ssb_close_all(tf_ssb_t* ssb, const char* reason); void tf_ssb_close_all(tf_ssb_t* ssb);
/** /**
** Send a graceful close message to all active SHS connections. ** Send a graceful close message to all active SHS connections.
@ -687,12 +676,12 @@ typedef void(tf_ssb_rpc_callback_t)(tf_ssb_connection_t* connection, uint8_t fla
/** /**
** Register a MUXRPC callback by name. ** Register a MUXRPC callback by name.
** @param ssb The SSB instance. ** @param ssb The SSB instance.
** @param name The RPC name as a .-separated string. ** @param name The NULL-terminated name.
** @param callback The callback. ** @param callback The callback.
** @param cleanup A function to be called when the callback is removed. ** @param cleanup A function to be called when the callback is removed.
** @param user_data User data to pass to the callback. ** @param user_data User data to pass to the callback.
*/ */
void tf_ssb_add_rpc_callback(tf_ssb_t* ssb, const char* name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data); void tf_ssb_add_rpc_callback(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
/** /**
** Remove a MUXRPC callback. ** Remove a MUXRPC callback.
@ -878,10 +867,9 @@ void tf_ssb_connection_remove_room_attendant(tf_ssb_connection_t* connection, co
** @param portal_id The identity of the tunnel intermediary. ** @param portal_id The identity of the tunnel intermediary.
** @param request_number The tunnel request. ** @param request_number The tunnel request.
** @param target_id The identity being tunneled to. ** @param target_id The identity being tunneled to.
** @param connect_flags Flags affecting the connection.
** @return The new tunnel connection. ** @return The new tunnel connection.
*/ */
tf_ssb_connection_t* tf_ssb_connection_tunnel_create(tf_ssb_t* ssb, const char* portal_id, int32_t request_number, const char* target_id, int connect_flags); tf_ssb_connection_t* tf_ssb_connection_tunnel_create(tf_ssb_t* ssb, const char* portal_id, int32_t request_number, const char* target_id);
/** /**
** Get the request number on which to send EBT responses. ** Get the request number on which to send EBT responses.
@ -1085,26 +1073,4 @@ void tf_ssb_connection_adjust_read_backpressure(tf_ssb_connection_t* connection,
*/ */
void tf_ssb_connection_adjust_write_count(tf_ssb_connection_t* connection, int delta); void tf_ssb_connection_adjust_write_count(tf_ssb_connection_t* connection, int delta);
/**
** Initiate a tunnel connection.
** @param ssb The SSB instance.
** @param portal_id The public key of the instance through which to tunnel.
** @param target_id The public key of the instance with which to establish a connection.
** @param connect_flags Flags affecting the connection.
** @return true if the tunnel instance was found.
*/
bool tf_ssb_tunnel_create(tf_ssb_t* ssb, const char* portal_id, const char* target_id, int connect_flags);
/**
** Initiate a one time sync operation.
** @param ssb The SSB instance.
*/
void tf_ssb_sync_start(tf_ssb_t* ssb);
/**
** Get a connection's flags.
** @param connection The connection.
*/
int tf_ssb_connection_get_flags(tf_ssb_connection_t* connection);
/** @} */ /** @} */

View File

@ -155,7 +155,7 @@ static void _tf_ssb_import_recursive_add_files(tf_ssb_t* ssb, uv_loop_t* loop, J
} }
else else
{ {
tf_printf("Failed to scan directory %s: %s.\n", path, uv_strerror(r)); tf_printf("Failed to scan directory %s: %s.", path, uv_strerror(r));
} }
uv_fs_req_cleanup(&req); uv_fs_req_cleanup(&req);
} }
@ -260,7 +260,7 @@ void tf_ssb_import(tf_ssb_t* ssb, const char* user, const char* path)
} }
else else
{ {
tf_printf("Failed to scan directory %s: %s.\n", path, uv_strerror(r)); tf_printf("Failed to scan directory %s: %s.", path, uv_strerror(r));
} }
uv_fs_req_cleanup(&req); uv_fs_req_cleanup(&req);
} }

View File

@ -13,8 +13,8 @@
#include "sodium/crypto_secretbox.h" #include "sodium/crypto_secretbox.h"
#include "sodium/crypto_sign.h" #include "sodium/crypto_sign.h"
#include "sodium/randombytes.h" #include "sodium/randombytes.h"
#include "sqlite3.h"
#include "string.h" #include "string.h"
#include "sqlite3.h"
#include "uv.h" #include "uv.h"
#include <assert.h> #include <assert.h>
@ -360,109 +360,6 @@ static JSValue _tf_ssb_set_server_following_me(JSContext* context, JSValueConst
return result; return result;
} }
typedef struct _swap_with_server_identity_t
{
char server_id[k_id_base64_len];
char id[k_id_base64_len];
JSValue promise[2];
char* error;
char user[];
} swap_with_server_identity_t;
static void _tf_ssb_swap_with_server_identity_work(tf_ssb_t* ssb, void* user_data)
{
swap_with_server_identity_t* work = user_data;
if (tf_ssb_db_user_has_permission(ssb, work->user, "administration"))
{
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
char* error = NULL;
if (sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &error) == SQLITE_OK)
{
sqlite3_stmt* statement = NULL;
if (sqlite3_prepare(db, "UPDATE identities SET user = ? WHERE user = ? AND '@' || public_key = ?", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, work->user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, ":admin", -1, NULL) == SQLITE_OK &&
sqlite3_bind_text(statement, 3, work->server_id, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_DONE && sqlite3_changes(db) == 1 &&
sqlite3_reset(statement) == SQLITE_OK && sqlite3_bind_text(statement, 1, ":admin", -1, NULL) == SQLITE_OK &&
sqlite3_bind_text(statement, 2, work->user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 3, work->id, -1, NULL) == SQLITE_OK &&
sqlite3_step(statement) == SQLITE_DONE && sqlite3_changes(db) == 1)
{
error = NULL;
if (sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, &error) != SQLITE_OK)
{
work->error = error ? tf_strdup(error) : tf_strdup(sqlite3_errmsg(db));
}
}
else
{
work->error = tf_strdup(sqlite3_errmsg(db) ? sqlite3_errmsg(db) : "swap failed");
}
sqlite3_finalize(statement);
}
else
{
work->error = tf_strdup(sqlite3_errmsg(db));
}
}
else
{
work->error = error ? tf_strdup(error) : tf_strdup(sqlite3_errmsg(db));
}
tf_ssb_release_db_writer(ssb, db);
}
else
{
work->error = tf_strdup("not administrator");
}
}
static void _tf_ssb_swap_with_server_identity_after_work(tf_ssb_t* ssb, int status, void* user_data)
{
swap_with_server_identity_t* work = user_data;
JSContext* context = tf_ssb_get_context(ssb);
JSValue error = JS_UNDEFINED;
if (work->error)
{
JSValue arg = JS_ThrowInternalError(context, "%s", work->error);
JSValue exception = JS_GetException(context);
error = JS_Call(context, work->promise[1], JS_UNDEFINED, 1, &exception);
tf_free(work->error);
JS_FreeValue(context, exception);
JS_FreeValue(context, arg);
}
else
{
error = JS_Call(context, work->promise[0], JS_UNDEFINED, 0, NULL);
}
tf_util_report_error(context, error);
JS_FreeValue(context, error);
JS_FreeValue(context, work->promise[0]);
JS_FreeValue(context, work->promise[1]);
tf_free(work);
}
static JSValue _tf_ssb_swap_with_server_identity(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId);
JSValue result = JS_UNDEFINED;
if (ssb)
{
size_t user_length = 0;
const char* user = JS_ToCStringLen(context, &user_length, argv[0]);
const char* id = JS_ToCString(context, argv[1]);
swap_with_server_identity_t* work = tf_malloc(sizeof(swap_with_server_identity_t) + user_length + 1);
*work = (swap_with_server_identity_t) { 0 };
tf_ssb_whoami(ssb, work->server_id, sizeof(work->server_id));
snprintf(work->id, sizeof(work->id), "%s", id);
memcpy(work->user, user, user_length + 1);
result = JS_NewPromiseCapability(context, work->promise);
tf_ssb_run_work(ssb, _tf_ssb_swap_with_server_identity_work, _tf_ssb_swap_with_server_identity_after_work, work);
JS_FreeCString(context, user);
JS_FreeCString(context, id);
}
return result;
}
typedef struct _identities_visit_t typedef struct _identities_visit_t
{ {
JSContext* context; JSContext* context;
@ -1639,7 +1536,7 @@ static JSValue _tf_ssb_connect(JSContext* context, JSValueConst this_val, int ar
{ {
const char* address_str = JS_ToCString(context, args); const char* address_str = JS_ToCString(context, args);
tf_printf("Connecting to %s\n", address_str); tf_printf("Connecting to %s\n", address_str);
tf_ssb_connect_str(ssb, address_str, 0); tf_ssb_connect_str(ssb, address_str);
JS_FreeCString(context, address_str); JS_FreeCString(context, address_str);
} }
else else
@ -1656,7 +1553,7 @@ static JSValue _tf_ssb_connect(JSContext* context, JSValueConst this_val, int ar
tf_printf("Connecting to %s:%d\n", address_str, port_int); tf_printf("Connecting to %s:%d\n", address_str, port_int);
uint8_t pubkey_bin[k_id_bin_len]; uint8_t pubkey_bin[k_id_bin_len];
tf_ssb_id_str_to_bin(pubkey_bin, pubkey_str); tf_ssb_id_str_to_bin(pubkey_bin, pubkey_str);
tf_ssb_connect(ssb, address_str, port_int, pubkey_bin, 0); tf_ssb_connect(ssb, address_str, port_int, pubkey_bin);
} }
else else
{ {
@ -1929,15 +1826,37 @@ static JSValue _tf_ssb_remove_event_listener(JSContext* context, JSValueConst th
static JSValue _tf_ssb_createTunnel(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) static JSValue _tf_ssb_createTunnel(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{ {
JSValue result = JS_UNDEFINED;
tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId); tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId);
const char* portal_id = JS_ToCString(context, argv[0]); const char* portal_id = JS_ToCString(context, argv[0]);
const char* target_id = JS_ToCString(context, argv[1]); const char* target_id = JS_ToCString(context, argv[1]);
bool result = tf_ssb_tunnel_create(ssb, portal_id, target_id, 0); tf_ssb_connection_t* connection = tf_ssb_connection_get(ssb, portal_id);
if (connection)
{
int32_t request_number = tf_ssb_connection_next_request_number(connection);
JSValue message = JS_NewObject(context);
JSValue name = JS_NewArray(context);
JS_SetPropertyUint32(context, name, 0, JS_NewString(context, "tunnel"));
JS_SetPropertyUint32(context, name, 1, JS_NewString(context, "connect"));
JS_SetPropertyStr(context, message, "name", name);
JSValue arg = JS_NewObject(context);
JS_SetPropertyStr(context, arg, "portal", JS_NewString(context, portal_id));
JS_SetPropertyStr(context, arg, "target", JS_NewString(context, target_id));
JSValue args = JS_NewArray(context);
JS_SetPropertyUint32(context, args, 0, arg);
JS_SetPropertyStr(context, message, "args", args);
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "duplex"));
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, request_number, "tunnel.connect", message, NULL, NULL, NULL);
JS_FreeValue(context, message);
tf_ssb_connection_tunnel_create(ssb, portal_id, request_number, target_id);
result = JS_TRUE;
}
JS_FreeCString(context, target_id); JS_FreeCString(context, target_id);
JS_FreeCString(context, portal_id); JS_FreeCString(context, portal_id);
return result ? JS_TRUE : JS_FALSE; return result;
} }
enum enum
@ -1947,7 +1866,7 @@ enum
static bool _tf_ssb_get_private_key_curve25519(sqlite3* db, const char* user, const char* identity, uint8_t out_private_key[static crypto_sign_SECRETKEYBYTES]) static bool _tf_ssb_get_private_key_curve25519(sqlite3* db, const char* user, const char* identity, uint8_t out_private_key[static crypto_sign_SECRETKEYBYTES])
{ {
if (!user || !identity) if (!user || !identity || !out_private_key)
{ {
tf_printf("user=%p identity=%p out_private_key=%p\n", user, identity, out_private_key); tf_printf("user=%p identity=%p out_private_key=%p\n", user, identity, out_private_key);
return false; return false;
@ -2387,118 +2306,6 @@ static JSValue _tf_ssb_following(JSContext* context, JSValueConst this_val, int
return result; return result;
} }
static JSValue _tf_ssb_sync(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId);
tf_ssb_sync_start(ssb);
return JS_UNDEFINED;
}
typedef struct _set_user_permission_t
{
tf_ssb_t* ssb;
JSContext* context;
const char* user;
const char* package_owner;
const char* package_name;
const char* permission;
bool allow;
bool result;
JSValue promise[2];
} set_user_permission_t;
static void _tf_ssb_set_user_permission_work(tf_ssb_t* ssb, void* user_data)
{
set_user_permission_t* work = user_data;
JSMallocFunctions funcs = { 0 };
tf_get_js_malloc_functions(&funcs);
JSRuntime* runtime = JS_NewRuntime2(&funcs, NULL);
JSContext* context = JS_NewContext(runtime);
/* XXX: Do this with one DB writer. */
const char* settings = tf_ssb_db_get_property(ssb, "core", "settings");
if (settings)
{
JSValue settings_value = JS_ParseJSON(context, settings, strlen(settings), NULL);
JSValue user_permissions = JS_GetPropertyStr(context, settings_value, "userPermissions");
if (JS_IsUndefined(user_permissions))
{
user_permissions = JS_NewObject(context);
JS_SetPropertyStr(context, settings_value, "userPermissions", JS_DupValue(context, user_permissions));
}
JSValue user = JS_GetPropertyStr(context, user_permissions, work->user);
if (JS_IsUndefined(user))
{
user = JS_NewObject(context);
JS_SetPropertyStr(context, user_permissions, work->user, JS_DupValue(context, user));
}
JSValue package_owner = JS_GetPropertyStr(context, user, work->package_owner);
if (JS_IsUndefined(package_owner))
{
package_owner = JS_NewObject(context);
JS_SetPropertyStr(context, user, work->package_owner, JS_DupValue(context, package_owner));
}
JSValue package_name = JS_GetPropertyStr(context, package_owner, work->package_name);
if (JS_IsUndefined(package_name))
{
package_name = JS_NewObject(context);
JS_SetPropertyStr(context, package_owner, work->package_name, package_name);
}
JSValue permission = JS_GetPropertyStr(context, package_name, work->permission);
if (JS_ToBool(context, permission) != work->allow)
{
JS_SetPropertyStr(context, package_name, work->permission, JS_NewBool(context, work->allow));
JSValue settings_json = JS_JSONStringify(context, settings_value, JS_NULL, JS_NULL);
const char* settings_string = JS_ToCString(context, settings_json);
work->result = tf_ssb_db_set_property(ssb, "core", "settings", settings_string);
JS_FreeCString(context, settings_string);
JS_FreeValue(context, settings_json);
}
else
{
work->result = true;
}
}
JS_FreeContext(context);
JS_FreeRuntime(runtime);
}
static void _tf_ssb_set_user_permission_after_work(tf_ssb_t* ssb, int status, void* user_data)
{
set_user_permission_t* work = user_data;
JSContext* context = work->context;
JS_FreeCString(context, work->user);
JS_FreeCString(context, work->package_owner);
JS_FreeCString(context, work->package_name);
JS_FreeCString(context, work->permission);
JSValue error = JS_Call(context, work->result ? work->promise[0] : work->promise[0], JS_UNDEFINED, 0, NULL);
tf_util_report_error(context, error);
JS_FreeValue(context, error);
JS_FreeValue(context, work->promise[0]);
JS_FreeValue(context, work->promise[1]);
tf_free(work);
}
static JSValue _tf_ssb_set_user_permission(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
set_user_permission_t* set = tf_malloc(sizeof(set_user_permission_t));
*set = (set_user_permission_t)
{
.ssb = JS_GetOpaque(this_val, _tf_ssb_classId),
.context = context,
.user = JS_ToCString(context, argv[0]),
.package_owner = JS_ToCString(context, argv[1]),
.package_name = JS_ToCString(context, argv[2]),
.permission = JS_ToCString(context, argv[3]),
.allow = JS_ToBool(context, argv[4]),
};
JSValue result = JS_NewPromiseCapability(context, set->promise);
tf_ssb_run_work(set->ssb, _tf_ssb_set_user_permission_work, _tf_ssb_set_user_permission_after_work, set);
return result;
}
void tf_ssb_register(JSContext* context, tf_ssb_t* ssb) void tf_ssb_register(JSContext* context, tf_ssb_t* ssb)
{ {
JS_NewClassID(&_tf_ssb_classId); JS_NewClassID(&_tf_ssb_classId);
@ -2520,12 +2327,10 @@ void tf_ssb_register(JSContext* context, tf_ssb_t* ssb)
JS_SetPropertyStr(context, object, "addIdentity", JS_NewCFunction(context, _tf_ssb_addIdentity, "addIdentity", 2)); JS_SetPropertyStr(context, object, "addIdentity", JS_NewCFunction(context, _tf_ssb_addIdentity, "addIdentity", 2));
JS_SetPropertyStr(context, object, "deleteIdentity", JS_NewCFunction(context, _tf_ssb_deleteIdentity, "deleteIdentity", 2)); JS_SetPropertyStr(context, object, "deleteIdentity", JS_NewCFunction(context, _tf_ssb_deleteIdentity, "deleteIdentity", 2));
JS_SetPropertyStr(context, object, "setServerFollowingMe", JS_NewCFunction(context, _tf_ssb_set_server_following_me, "setServerFollowingMe", 3)); JS_SetPropertyStr(context, object, "setServerFollowingMe", JS_NewCFunction(context, _tf_ssb_set_server_following_me, "setServerFollowingMe", 3));
JS_SetPropertyStr(context, object, "swapWithServerIdentity", JS_NewCFunction(context, _tf_ssb_swap_with_server_identity, "swapWithServerIdentity", 2));
JS_SetPropertyStr(context, object, "getIdentities", JS_NewCFunction(context, _tf_ssb_getIdentities, "getIdentities", 1)); JS_SetPropertyStr(context, object, "getIdentities", JS_NewCFunction(context, _tf_ssb_getIdentities, "getIdentities", 1));
JS_SetPropertyStr(context, object, "getPrivateKey", JS_NewCFunction(context, _tf_ssb_getPrivateKey, "getPrivateKey", 2)); JS_SetPropertyStr(context, object, "getPrivateKey", JS_NewCFunction(context, _tf_ssb_getPrivateKey, "getPrivateKey", 2));
JS_SetPropertyStr(context, object, "privateMessageEncrypt", JS_NewCFunction(context, _tf_ssb_private_message_encrypt, "privateMessageEncrypt", 4)); JS_SetPropertyStr(context, object, "privateMessageEncrypt", JS_NewCFunction(context, _tf_ssb_private_message_encrypt, "privateMessageEncrypt", 4));
JS_SetPropertyStr(context, object, "privateMessageDecrypt", JS_NewCFunction(context, _tf_ssb_private_message_decrypt, "privateMessageDecrypt", 3)); JS_SetPropertyStr(context, object, "privateMessageDecrypt", JS_NewCFunction(context, _tf_ssb_private_message_decrypt, "privateMessageDecrypt", 3));
JS_SetPropertyStr(context, object, "setUserPermission", JS_NewCFunction(context, _tf_ssb_set_user_permission, "setUserPermission", 5));
/* Write. */ /* Write. */
JS_SetPropertyStr(context, object, "appendMessageWithIdentity", JS_NewCFunction(context, _tf_ssb_appendMessageWithIdentity, "appendMessageWithIdentity", 3)); JS_SetPropertyStr(context, object, "appendMessageWithIdentity", JS_NewCFunction(context, _tf_ssb_appendMessageWithIdentity, "appendMessageWithIdentity", 3));
@ -2545,7 +2350,6 @@ void tf_ssb_register(JSContext* context, tf_ssb_t* ssb)
JS_SetPropertyStr(context, object, "connect", JS_NewCFunction(context, _tf_ssb_connect, "connect", 1)); JS_SetPropertyStr(context, object, "connect", JS_NewCFunction(context, _tf_ssb_connect, "connect", 1));
JS_SetPropertyStr(context, object, "createTunnel", JS_NewCFunction(context, _tf_ssb_createTunnel, "createTunnel", 3)); JS_SetPropertyStr(context, object, "createTunnel", JS_NewCFunction(context, _tf_ssb_createTunnel, "createTunnel", 3));
JS_SetPropertyStr(context, object, "following", JS_NewCFunction(context, _tf_ssb_following, "following", 2)); JS_SetPropertyStr(context, object, "following", JS_NewCFunction(context, _tf_ssb_following, "following", 2));
JS_SetPropertyStr(context, object, "sync", JS_NewCFunction(context, _tf_ssb_sync, "sync", 0));
/* Write. */ /* Write. */
JS_SetPropertyStr(context, object, "storeMessage", JS_NewCFunction(context, _tf_ssb_storeMessage, "storeMessage", 1)); JS_SetPropertyStr(context, object, "storeMessage", JS_NewCFunction(context, _tf_ssb_storeMessage, "storeMessage", 1));
JS_SetPropertyStr(context, object, "blobStore", JS_NewCFunction(context, _tf_ssb_blobStore, "blobStore", 1)); JS_SetPropertyStr(context, object, "blobStore", JS_NewCFunction(context, _tf_ssb_blobStore, "blobStore", 1));

View File

@ -2,8 +2,8 @@
#include "log.h" #include "log.h"
#include "mem.h" #include "mem.h"
#include "ssb.db.h"
#include "ssb.h" #include "ssb.h"
#include "ssb.db.h"
#include "util.js.h" #include "util.js.h"
#include "sqlite3.h" #include "sqlite3.h"
@ -106,7 +106,6 @@ static void _tf_ssb_rpc_blobs_get(tf_ssb_connection_t* connection, uint8_t flags
{ {
if (flags & k_ssb_rpc_flag_end_error) if (flags & k_ssb_rpc_flag_end_error)
{ {
tf_ssb_connection_remove_request(connection, -request_number);
return; return;
} }
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection); tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
@ -256,8 +255,6 @@ static void _tf_ssb_request_blob_wants_work(tf_ssb_connection_t* connection, voi
static void _tf_ssb_request_blob_wants_after_work(tf_ssb_connection_t* connection, int result, void* user_data) static void _tf_ssb_request_blob_wants_after_work(tf_ssb_connection_t* connection, int result, void* user_data)
{ {
blob_wants_work_t* work = user_data; blob_wants_work_t* work = user_data;
if (!tf_ssb_is_shutting_down(tf_ssb_connection_get_ssb(connection)))
{
JSContext* context = tf_ssb_connection_get_context(connection); JSContext* context = tf_ssb_connection_get_context(connection);
tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection); tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection);
for (int i = 0; i < work->out_id_count; i++) for (int i = 0; i < work->out_id_count; i++)
@ -272,7 +269,6 @@ static void _tf_ssb_request_blob_wants_after_work(tf_ssb_connection_t* connectio
{ {
snprintf(blob_wants->last_id, sizeof(blob_wants->last_id), "%s", work->out_id[work->out_id_count - 1]); snprintf(blob_wants->last_id, sizeof(blob_wants->last_id), "%s", work->out_id[work->out_id_count - 1]);
} }
}
tf_free(work); tf_free(work);
} }
@ -395,7 +391,7 @@ static void _tf_ssb_rpc_tunnel_connect(tf_ssb_connection_t* connection, uint8_t
const char* origin_str = JS_ToCString(context, origin); const char* origin_str = JS_ToCString(context, origin);
const char* portal_str = JS_ToCString(context, portal); const char* portal_str = JS_ToCString(context, portal);
const char* target_str = JS_ToCString(context, target); const char* target_str = JS_ToCString(context, target);
tf_ssb_connection_tunnel_create(ssb, portal_str, -request_number, origin_str, 0); tf_ssb_connection_tunnel_create(ssb, portal_str, -request_number, origin_str);
JS_FreeCString(context, origin_str); JS_FreeCString(context, origin_str);
JS_FreeCString(context, portal_str); JS_FreeCString(context, portal_str);
JS_FreeCString(context, target_str); JS_FreeCString(context, target_str);
@ -858,12 +854,11 @@ static void _tf_ssb_connection_send_history_stream_after_work(tf_ssb_connection_
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_json, request->request_number, NULL, (const uint8_t*)request->out_messages[i], tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_json, request->request_number, NULL, (const uint8_t*)request->out_messages[i],
strlen(request->out_messages[i]), NULL, NULL, NULL); strlen(request->out_messages[i]), NULL, NULL, NULL);
} }
bool live = request->live && (tf_ssb_connection_get_flags(connection) & k_tf_ssb_connect_flag_one_shot) == 0;
if (!request->out_finished) if (!request->out_finished)
{ {
_tf_ssb_connection_send_history_stream(connection, request->request_number, request->author, request->out_max_sequence_seen, request->keys, live); _tf_ssb_connection_send_history_stream(connection, request->request_number, request->author, request->out_max_sequence_seen, request->keys, request->live);
} }
else if (!live) else if (!request->live)
{ {
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_json, request->request_number, NULL, (const uint8_t*)"false", strlen("false"), NULL, NULL, NULL); tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_json, request->request_number, NULL, (const uint8_t*)"false", strlen("false"), NULL, NULL, NULL);
} }
@ -923,7 +918,7 @@ static void _tf_ssb_rpc_createHistoryStream(
JSValue keys = JS_GetPropertyStr(context, arg, "keys"); JSValue keys = JS_GetPropertyStr(context, arg, "keys");
JSValue live = JS_GetPropertyStr(context, arg, "live"); JSValue live = JS_GetPropertyStr(context, arg, "live");
bool is_keys = JS_IsUndefined(keys) || JS_ToBool(context, keys) > 0; bool is_keys = JS_IsUndefined(keys) || JS_ToBool(context, keys) > 0;
bool is_live = JS_ToBool(context, live) > 0 && (tf_ssb_connection_get_flags(connection) & k_tf_ssb_connect_flag_one_shot) == 0; bool is_live = JS_ToBool(context, live) > 0;
int64_t sequence = 0; int64_t sequence = 0;
JS_ToInt64(context, &sequence, seq); JS_ToInt64(context, &sequence, seq);
const char* author = JS_ToCString(context, id); const char* author = JS_ToCString(context, id);
@ -1109,13 +1104,9 @@ static void _tf_ssb_rpc_ebt_replicate_send_messages(tf_ssb_connection_t* connect
if (sequence >= 0 && (sequence & 1) == 0) if (sequence >= 0 && (sequence & 1) == 0)
{ {
int32_t request_number = tf_ssb_connection_get_ebt_request_number(connection); int32_t request_number = tf_ssb_connection_get_ebt_request_number(connection);
bool live = (tf_ssb_connection_get_flags(connection) & k_tf_ssb_connect_flag_one_shot) == 0; _tf_ssb_connection_send_history_stream(connection, request_number, author, sequence >> 1, false, true);
_tf_ssb_connection_send_history_stream(connection, request_number, author, sequence >> 1, false, live);
if (live)
{
tf_ssb_connection_add_new_message_request(connection, author, request_number, false); tf_ssb_connection_add_new_message_request(connection, author, request_number, false);
} }
}
else else
{ {
tf_ssb_connection_remove_new_message_request(connection, author); tf_ssb_connection_remove_new_message_request(connection, author);
@ -1295,26 +1286,6 @@ static void _tf_ssb_rpc_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_chang
} }
} }
static void _tf_ssb_rpc_broadcasts_changed_visit(
const char* host, const struct sockaddr_in* addr, tf_ssb_broadcast_origin_t origin, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
{
tf_ssb_t* ssb = user_data;
if (tunnel && (tf_ssb_connection_get_flags(tunnel) & k_tf_ssb_connect_flag_one_shot) != 0 && !tf_ssb_connection_get_tunnel(tunnel))
{
char target_id[k_id_base64_len] = { 0 };
char portal_id[k_id_base64_len] = { 0 };
if (tf_ssb_id_bin_to_str(target_id, sizeof(target_id), pub) && tf_ssb_connection_get_id(tunnel, portal_id, sizeof(portal_id)))
{
tf_ssb_tunnel_create(ssb, portal_id, target_id, k_tf_ssb_connect_flag_one_shot);
}
}
}
static void _tf_ssb_rpc_broadcasts_changed_callback(tf_ssb_t* ssb, void* user_data)
{
tf_ssb_visit_broadcasts(ssb, _tf_ssb_rpc_broadcasts_changed_visit, ssb);
}
static void _tf_ssb_rpc_checkpoint(tf_ssb_t* ssb) static void _tf_ssb_rpc_checkpoint(tf_ssb_t* ssb)
{ {
int64_t checkpoint_start_ms = uv_hrtime(); int64_t checkpoint_start_ms = uv_hrtime();
@ -1540,16 +1511,15 @@ static void _tf_ssb_rpc_peers_exchange(tf_ssb_connection_t* connection, uint8_t
void tf_ssb_rpc_register(tf_ssb_t* ssb) void tf_ssb_rpc_register(tf_ssb_t* ssb)
{ {
tf_ssb_add_connections_changed_callback(ssb, _tf_ssb_rpc_connections_changed_callback, NULL, NULL); tf_ssb_add_connections_changed_callback(ssb, _tf_ssb_rpc_connections_changed_callback, NULL, NULL);
tf_ssb_add_broadcasts_changed_callback(ssb, _tf_ssb_rpc_broadcasts_changed_callback, NULL, NULL); tf_ssb_add_rpc_callback(ssb, (const char*[]) { "gossip", "ping", NULL }, _tf_ssb_rpc_gossip_ping, NULL, NULL); /* DUPLEX */
tf_ssb_add_rpc_callback(ssb, "gossip.ping", _tf_ssb_rpc_gossip_ping, NULL, NULL); /* DUPLEX */ tf_ssb_add_rpc_callback(ssb, (const char*[]) { "blobs", "get", NULL }, _tf_ssb_rpc_blobs_get, NULL, NULL); /* SOURCE */
tf_ssb_add_rpc_callback(ssb, "blobs.get", _tf_ssb_rpc_blobs_get, NULL, NULL); /* SOURCE */ tf_ssb_add_rpc_callback(ssb, (const char*[]) { "blobs", "has", NULL }, _tf_ssb_rpc_blobs_has, NULL, NULL); /* ASYNC */
tf_ssb_add_rpc_callback(ssb, "blobs.has", _tf_ssb_rpc_blobs_has, NULL, NULL); /* ASYNC */ tf_ssb_add_rpc_callback(ssb, (const char*[]) { "blobs", "createWants", NULL }, _tf_ssb_rpc_blobs_createWants, NULL, NULL); /* SOURCE */
tf_ssb_add_rpc_callback(ssb, "blobs.createWants", _tf_ssb_rpc_blobs_createWants, NULL, NULL); /* SOURCE */ tf_ssb_add_rpc_callback(ssb, (const char*[]) { "tunnel", "connect", NULL }, _tf_ssb_rpc_tunnel_connect, NULL, NULL); /* DUPLEX */
tf_ssb_add_rpc_callback(ssb, "tunnel.connect", _tf_ssb_rpc_tunnel_connect, NULL, NULL); /* DUPLEX */ tf_ssb_add_rpc_callback(ssb, (const char*[]) { "tunnel", "isRoom", NULL }, _tf_ssb_rpc_room_meta, NULL, NULL); /* FAKE-ASYNC */
tf_ssb_add_rpc_callback(ssb, "tunnel.isRoom", _tf_ssb_rpc_room_meta, NULL, NULL); /* FAKE-ASYNC */ tf_ssb_add_rpc_callback(ssb, (const char*[]) { "room", "metadata", NULL }, _tf_ssb_rpc_room_meta, NULL, NULL); /* ASYNC */
tf_ssb_add_rpc_callback(ssb, "room.metadata", _tf_ssb_rpc_room_meta, NULL, NULL); /* ASYNC */ tf_ssb_add_rpc_callback(ssb, (const char*[]) { "room", "attendants", NULL }, _tf_ssb_rpc_room_attendants, NULL, NULL); /* SOURCE */
tf_ssb_add_rpc_callback(ssb, "room.attendants", _tf_ssb_rpc_room_attendants, NULL, NULL); /* SOURCE */ tf_ssb_add_rpc_callback(ssb, (const char*[]) { "createHistoryStream", NULL }, _tf_ssb_rpc_createHistoryStream, NULL, NULL); /* SOURCE */
tf_ssb_add_rpc_callback(ssb, "createHistoryStream", _tf_ssb_rpc_createHistoryStream, NULL, NULL); /* SOURCE */ tf_ssb_add_rpc_callback(ssb, (const char*[]) { "ebt", "replicate", NULL }, _tf_ssb_rpc_ebt_replicate_server, NULL, NULL); /* DUPLEX */
tf_ssb_add_rpc_callback(ssb, "ebt.replicate", _tf_ssb_rpc_ebt_replicate_server, NULL, NULL); /* DUPLEX */ tf_ssb_add_rpc_callback(ssb, (const char*[]) { "peers", "exchange", NULL }, _tf_ssb_rpc_peers_exchange, NULL, NULL); /* ASYNC */
tf_ssb_add_rpc_callback(ssb, "peers.exchange", _tf_ssb_rpc_peers_exchange, NULL, NULL); /* ASYNC */
} }

View File

@ -245,7 +245,7 @@ void tf_ssb_test_ssb(const tf_test_options_t* options)
uint8_t id0bin[k_id_bin_len]; uint8_t id0bin[k_id_bin_len];
tf_ssb_id_str_to_bin(id0bin, id0); tf_ssb_id_str_to_bin(id0bin, id0);
tf_ssb_connect(ssb1, "127.0.0.1", 12347, id0bin, 0); tf_ssb_connect(ssb1, "127.0.0.1", 12347, id0bin);
tf_printf("Waiting for connection.\n"); tf_printf("Waiting for connection.\n");
while (test.connection_count0 != 1 || test.connection_count1 != 1) while (test.connection_count0 != 1 || test.connection_count1 != 1)
@ -457,8 +457,8 @@ void tf_ssb_test_rooms(const tf_test_options_t* options)
uint8_t id0bin[k_id_bin_len]; uint8_t id0bin[k_id_bin_len];
tf_ssb_id_str_to_bin(id0bin, id0); tf_ssb_id_str_to_bin(id0bin, id0);
tf_ssb_connect(ssb1, "127.0.0.1", 12347, id0bin, 0); tf_ssb_connect(ssb1, "127.0.0.1", 12347, id0bin);
tf_ssb_connect(ssb2, "127.0.0.1", 12347, id0bin, 0); tf_ssb_connect(ssb2, "127.0.0.1", 12347, id0bin);
tf_printf("Waiting for connection.\n"); tf_printf("Waiting for connection.\n");
while (test.connection_count0 != 2 || test.connection_count1 != 1 || test.connection_count2 != 1) while (test.connection_count0 != 2 || test.connection_count1 != 1 || test.connection_count2 != 1)
@ -497,7 +497,7 @@ void tf_ssb_test_rooms(const tf_test_options_t* options)
tf_ssb_connection_rpc_send_json(connections[0], k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, tunnel_request_number, "tunnel.connect", message, NULL, NULL, NULL); tf_ssb_connection_rpc_send_json(connections[0], k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, tunnel_request_number, "tunnel.connect", message, NULL, NULL, NULL);
JS_FreeValue(context, message); JS_FreeValue(context, message);
tf_ssb_connection_t* tun0 = tf_ssb_connection_tunnel_create(ssb1, id0, tunnel_request_number, id2, 0); tf_ssb_connection_t* tun0 = tf_ssb_connection_tunnel_create(ssb1, id0, tunnel_request_number, id2);
tf_printf("tun0 = %p\n", tun0); tf_printf("tun0 = %p\n", tun0);
tf_printf("Done.\n"); tf_printf("Done.\n");
@ -523,9 +523,9 @@ void tf_ssb_test_rooms(const tf_test_options_t* options)
tf_ssb_send_close(ssb1); tf_ssb_send_close(ssb1);
tf_ssb_send_close(ssb2); tf_ssb_send_close(ssb2);
tf_ssb_close_all(ssb0, "end of test"); tf_ssb_close_all(ssb0);
tf_ssb_close_all(ssb1, "end of test"); tf_ssb_close_all(ssb1);
tf_ssb_close_all(ssb2, "end of test"); tf_ssb_close_all(ssb2);
uv_run(&loop, UV_RUN_DEFAULT); uv_run(&loop, UV_RUN_DEFAULT);
@ -689,7 +689,7 @@ void tf_ssb_test_bench(const tf_test_options_t* options)
tf_ssb_register(tf_ssb_get_context(ssb1), ssb1); tf_ssb_register(tf_ssb_get_context(ssb1), ssb1);
tf_ssb_server_open(ssb0, 12347); tf_ssb_server_open(ssb0, 12347);
tf_ssb_connect(ssb1, "127.0.0.1", 12347, id0bin, 0); tf_ssb_connect(ssb1, "127.0.0.1", 12347, id0bin);
tf_printf("Waiting for messages.\n"); tf_printf("Waiting for messages.\n");
clock_gettime(CLOCK_REALTIME, &start_time); clock_gettime(CLOCK_REALTIME, &start_time);
@ -824,7 +824,7 @@ static void _ssb_test_room_broadcasts_visit(
JS_FreeValue(context, message); JS_FreeValue(context, message);
tf_printf("tunnel create ssb=%p portal=%s rn=%d target=%s\n", ssb, portal, (int)tunnel_request_number, target); tf_printf("tunnel create ssb=%p portal=%s rn=%d target=%s\n", ssb, portal, (int)tunnel_request_number, target);
tf_ssb_connection_tunnel_create(ssb, portal, tunnel_request_number, target, 0); tf_ssb_connection_tunnel_create(ssb, portal, tunnel_request_number, target);
_break_in_a_bit(ssb, tunnel, target, tunnel_request_number); _break_in_a_bit(ssb, tunnel, target, tunnel_request_number);
} }
} }
@ -858,8 +858,8 @@ void tf_ssb_test_go_ssb_room(const tf_test_options_t* options)
tf_ssb_add_broadcasts_changed_callback(ssb0, _ssb_test_room_broadcasts_changed, NULL, NULL); tf_ssb_add_broadcasts_changed_callback(ssb0, _ssb_test_room_broadcasts_changed, NULL, NULL);
tf_ssb_connect_str(ssb0, "net:linode.unprompted.com:8008~shs:Q0pc/7kXQJGIlqJxuwayL2huayzddgkVDoGkYVWQS1Y=:SSB+Room+PSK3TLYC2T86EHQCUHBUHASCASE18JBV24=", 0); tf_ssb_connect_str(ssb0, "net:linode.unprompted.com:8008~shs:Q0pc/7kXQJGIlqJxuwayL2huayzddgkVDoGkYVWQS1Y=:SSB+Room+PSK3TLYC2T86EHQCUHBUHASCASE18JBV24=");
tf_ssb_connect_str(ssb1, "net:linode.unprompted.com:8008~shs:Q0pc/7kXQJGIlqJxuwayL2huayzddgkVDoGkYVWQS1Y=:SSB+Room+PSK3TLYC2T86EHQCUHBUHASCASE18JBV24=", 0); tf_ssb_connect_str(ssb1, "net:linode.unprompted.com:8008~shs:Q0pc/7kXQJGIlqJxuwayL2huayzddgkVDoGkYVWQS1Y=:SSB+Room+PSK3TLYC2T86EHQCUHBUHASCASE18JBV24=");
uv_run(&loop, UV_RUN_DEFAULT); uv_run(&loop, UV_RUN_DEFAULT);
@ -959,8 +959,8 @@ void tf_ssb_test_peer_exchange(const tf_test_options_t* options)
tf_ssb_whoami(ssb0, id0, sizeof(id0)); tf_ssb_whoami(ssb0, id0, sizeof(id0));
uint8_t id0bin[k_id_bin_len]; uint8_t id0bin[k_id_bin_len];
tf_ssb_id_str_to_bin(id0bin, id0); tf_ssb_id_str_to_bin(id0bin, id0);
tf_ssb_connect(ssb1, "127.0.0.1", 12347, id0bin, 0); tf_ssb_connect(ssb1, "127.0.0.1", 12347, id0bin);
tf_ssb_connect(ssb2, "127.0.0.1", 12347, id0bin, 0); tf_ssb_connect(ssb2, "127.0.0.1", 12347, id0bin);
while (_count_broadcasts(ssb0) != 2 || _count_broadcasts(ssb1) != 1 || _count_broadcasts(ssb2) != 1) while (_count_broadcasts(ssb0) != 2 || _count_broadcasts(ssb1) != 1 || _count_broadcasts(ssb2) != 1)
{ {

View File

@ -27,12 +27,12 @@
#include <openssl/crypto.h> #include <openssl/crypto.h>
#include <assert.h> #include <assert.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#if !defined(_WIN32) #if !defined(_WIN32)
#include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <sys/wait.h>
#endif #endif
#if defined(_WIN32) #if defined(_WIN32)

View File

@ -7,8 +7,8 @@
#include "task.h" #include "task.h"
#include "util.js.h" #include "util.js.h"
#include <stdio.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#ifdef _WIN32 #ifdef _WIN32
#include <io.h> #include <io.h>

View File

@ -9,8 +9,8 @@
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>

View File

@ -5,8 +5,8 @@
#include "task.h" #include "task.h"
#include "tls.h" #include "tls.h"
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
static JSClassID _classId; static JSClassID _classId;
static int _count; static int _count;

View File

@ -1,2 +1,2 @@
#define VERSION_NUMBER "0.0.24-wip" #define VERSION_NUMBER "0.0.23"
#define VERSION_NAME "Honey bunches of boats." #define VERSION_NAME "Me upon my pony on my boat."

View File

@ -1,7 +1,8 @@
VERSION=3.2.1 VERSION=3.2.0
wget https://cdn.jsdelivr.net/gh/lit/dist@$VERSION/all/lit-all.min.js -O deps/lit/lit-all.min.js wget https://cdn.jsdelivr.net/gh/lit/dist@$VERSION/all/lit-all.min.js -O deps/lit/lit-all.min.js
wget https://cdn.jsdelivr.net/gh/lit/dist@$VERSION/all/lit-all.min.js.map -O deps/lit/lit-all.min.js.map wget https://cdn.jsdelivr.net/gh/lit/dist@$VERSION/all/lit-all.min.js.map -O deps/lit/lit-all.min.js.map
cp -fv deps/lit/* apps/blog/ cp -fv deps/lit/* apps/blog/
cp -fv deps/lit/* apps/gg/
cp -fv deps/lit/* apps/issues/ cp -fv deps/lit/* apps/issues/
cp -fv deps/lit/* apps/journal/ cp -fv deps/lit/* apps/journal/
cp -fv deps/lit/* apps/sneaker/ cp -fv deps/lit/* apps/sneaker/