Compare commits
No commits in common. "main" and "v0.0.23" have entirely different histories.
@ -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
|
||||||
...
|
...
|
||||||
|
@ -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
|
||||||
|
205
GNUmakefile
205
GNUmakefile
@ -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
|
||||||
|
20
README.md
20
README.md
@ -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
|
||||||
|
2
apps/blog/commonmark.min.js
vendored
2
apps/blog/commonmark.min.js
vendored
File diff suppressed because one or more lines are too long
44
apps/blog/lit-all.min.js
vendored
44
apps/blog/lit-all.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🪪",
|
"emoji": "🪪",
|
||||||
"previous": "&5kw/2PgcySwOYCmAkjHTR2xTkIx3i7UjQmtQ8MfgWw8=.sha256"
|
"previous": "&zxsmzdLKsiG/WZt/Gw7JOxepgypoktNNbIyWiyFiJVc=.sha256"
|
||||||
}
|
}
|
||||||
|
@ -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>`
|
||||||
)
|
)
|
||||||
|
2
apps/issues/commonmark.min.js
vendored
2
apps/issues/commonmark.min.js
vendored
File diff suppressed because one or more lines are too long
44
apps/issues/lit-all.min.js
vendored
44
apps/issues/lit-all.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
apps/journal/commonmark.min.js
vendored
2
apps/journal/commonmark.min.js
vendored
File diff suppressed because one or more lines are too long
44
apps/journal/lit-all.min.js
vendored
44
apps/journal/lit-all.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
44
apps/sneaker/lit-all.min.js
vendored
44
apps/sneaker/lit-all.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🐌",
|
"emoji": "🐌",
|
||||||
"previous": "&CsZ2FBYY9awXNPPHAhTlrOHuKlGU6RXZJ3UTV3UQRIE=.sha256"
|
"previous": "&7L314QLuVl8kNbFIWuXXeLqIVefUe5S66WvEmOMQb2U=.sha256"
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
});
|
});
|
||||||
|
2
apps/ssb/commonmark.min.js
vendored
2
apps/ssb/commonmark.min.js
vendored
File diff suppressed because one or more lines are too long
44
apps/ssb/lit-all.min.js
vendored
44
apps/ssb/lit-all.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -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() {
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
/>`;
|
/>`;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "👋",
|
"emoji": "👋",
|
||||||
"previous": "&7gFmLW5zSMhmxWWY1+jeRcHdullgujSqGJg94lVgr1k=.sha256"
|
"previous": "&7Pqk5nBAcbjzp0etv6WgiyTD3UF++ID0mW6qIbhwt3s=.sha256"
|
||||||
}
|
}
|
||||||
|
@ -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 |
@ -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 |
@ -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 |
@ -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>
|
||||||
|
2
apps/wiki/commonmark.min.js
vendored
2
apps/wiki/commonmark.min.js
vendored
File diff suppressed because one or more lines are too long
44
apps/wiki/lit-all.min.js
vendored
44
apps/wiki/lit-all.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -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
|
||||||
|
@ -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');
|
||||||
|
241
core/core.js
241
core/core.js
@ -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};
|
||||||
|
@ -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
2
deps/c-ares
vendored
@ -1 +1 @@
|
|||||||
Subproject commit a57ff692eeab8d21c853dc1ddaf0164f517074c3
|
Subproject commit 27b98d96eff6122fb981e338bddef3d6a57d8d44
|
2
deps/codemirror/cm6.js
vendored
2
deps/codemirror/cm6.js
vendored
File diff suppressed because one or more lines are too long
224
deps/codemirror_src/package-lock.json
generated
vendored
224
deps/codemirror_src/package-lock.json
generated
vendored
@ -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
2
deps/libuv
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 8be336f4ee296d20e1c071a44d6adf279e202236
|
Subproject commit d2e56a5e8d3e39947b78405ca6e4727c70f5568a
|
44
deps/lit/lit-all.min.js
vendored
44
deps/lit/lit-all.min.js
vendored
File diff suppressed because one or more lines are too long
2
deps/lit/lit-all.min.js.map
vendored
2
deps/lit/lit-all.min.js.map
vendored
File diff suppressed because one or more lines are too long
4
package-lock.json
generated
4
package-lock.json
generated
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
{
|
{
|
||||||
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
141
src/httpd.js.c
141
src/httpd.js.c
@ -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.
@ -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;
|
||||||
|
|
||||||
|
@ -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
269
src/ssb.c
@ -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;
|
|
||||||
}
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
@ -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);
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
46
src/ssb.h
46
src/ssb.h
@ -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);
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
252
src/ssb.js.c
252
src/ssb.js.c
@ -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));
|
||||||
|
@ -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 */
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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)
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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."
|
||||||
|
@ -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/
|
||||||
|
Loading…
Reference in New Issue
Block a user