Compare commits
286 Commits
Author | SHA1 | Date | |
---|---|---|---|
09ae4e2096 | |||
0b46efe4ea | |||
f1dda43e66 | |||
ce483138d7 | |||
73cc39226d | |||
57257f63dd | |||
88b25790e8 | |||
e01defc4aa | |||
cb50c43e93 | |||
5908d15f91 | |||
f66cfaec12 | |||
259f92c53b | |||
a84f850e91 | |||
5a765e6f07 | |||
791889c659 | |||
5da63faf1f | |||
30d108fc35 | |||
a09fefab5e | |||
f74ca1c236 | |||
30e027092b | |||
fd4ac7c9b9 | |||
4482049b94 | |||
5839380437 | |||
2152470fdc | |||
93b2a81495 | |||
e139e952c0 | |||
cf1c57ccb8 | |||
f7a2138488 | |||
9614d03bef | |||
32a335c676 | |||
06e27fc1e0 | |||
1f40e8dcd9 | |||
77ff8cef1f | |||
ef844fbccb | |||
070dc5a4c0 | |||
177ef1cdcc | |||
4b1ebf02e1 | |||
863e50203e | |||
01b8c209de | |||
30e92f2bc1 | |||
02accabb4a | |||
fa00a41fe0 | |||
2e66666bdf | |||
4fe3c9a751 | |||
0a35e14590 | |||
e979c176e3 | |||
a0d9c3dc29 | |||
efcb68351c | |||
94e8bf2e1c | |||
82d1a294a6 | |||
de20274589 | |||
2f193e64c8 | |||
86751362cb | |||
4118323631 | |||
0d134f7f10 | |||
409724cfcd | |||
799a33be40 | |||
2fa9c66495 | |||
ad818a8e7e | |||
581f72b3f8 | |||
1dd7e4347c | |||
36cc9398c7 | |||
68817feeec | |||
97661e2ca2 | |||
72def5ae6d | |||
e638b155a1 | |||
32db18b0d6 | |||
b653a5250d | |||
30329f7cad | |||
29a1478c86 | |||
c882bf31ec | |||
17ccb8f083 | |||
0e7d2a8b0e | |||
3743543ef8 | |||
700dd7b45a | |||
c2eb73fd8a | |||
e1f4f7f95b | |||
37401409c6 | |||
b282631cd5 | |||
9618d3b3f3 | |||
c9f997d121 | |||
f1dee2a089 | |||
8273277c91 | |||
9758844da3 | |||
e41c7fbbc7 | |||
24db8a5a49 | |||
36e82b9873 | |||
8a32f2b8b1 | |||
277830bc3c | |||
a8fa969114 | |||
c3f3dced68 | |||
85fce59c0c | |||
8a6147d512 | |||
e799b256b2 | |||
b222dc0ca8 | |||
c52c6b04ca | |||
b95eed46bb | |||
7c36a543da | |||
90e000c18e | |||
1bb9d737d8 | |||
9a5db2ec51 | |||
dbed29a044 | |||
681859531c | |||
8e1ad6b16a | |||
5448f1ba2d | |||
e43da4e1a3 | |||
eaa9da49cc | |||
40873b529c | |||
8cc4c19d73 | |||
bb9c18faf1 | |||
fabdfb76b9 | |||
bce263a928 | |||
195920e476 | |||
a821d895c5 | |||
ab1b6ec27d | |||
6dc099809f | |||
03c8b75994 | |||
38887452ad | |||
7512edad59 | |||
944c895bcd | |||
e7d87ee8e2 | |||
cfdbd10635 | |||
d3a2d8733f | |||
a7e623d817 | |||
3f0c37cea4 | |||
2c96a6d22a | |||
57b4214a72 | |||
433b3d39d9 | |||
26441ed45c | |||
92cd38c2a0 | |||
3b5a06794f | |||
d104409272 | |||
e5f58c2898 | |||
f83863ef01 | |||
837f069cf5 | |||
9f057dc29a | |||
c4904f176c | |||
d3a5aba703 | |||
9e283e427c | |||
133ba31d66 | |||
241a65a92a | |||
0b54795bab | |||
6208193de5 | |||
c53321532f | |||
34f25e3e06 | |||
c46244366e | |||
6518af04fc | |||
bf137ff1f7 | |||
1877955b62 | |||
50d0875de2 | |||
bf151e6b7d | |||
82893402d0 | |||
8049102787 | |||
f42cc3d9fd | |||
5f9a5208db | |||
6df506d238 | |||
2bd3354256 | |||
b55aaa1d18 | |||
34e19505bd | |||
6e06ec0904 | |||
a5814074fe | |||
d7479df5a2 | |||
34508aa0ae | |||
ae096b2c9c | |||
95d036e34a | |||
4af5e8ec42 | |||
2a5f71bd5d | |||
97fb63dda1 | |||
87d42e3b3b | |||
0394129a4c | |||
3c499c834b | |||
17d6cc7d46 | |||
646bd7dc38 | |||
56e483782d | |||
e1b9066b26 | |||
7114ce2516 | |||
9240c6570a | |||
f80a44ccd7 | |||
e6f5eb244e | |||
ab62e83110 | |||
aeefb9e536 | |||
ee0efa536a | |||
2523130fdc | |||
c024777184 | |||
5951d7cd2d | |||
011670c70b | |||
6cebd6c769 | |||
546ae5cbf1 | |||
f543cc642e | |||
8ac3c5ea22 | |||
63918f0680 | |||
bfb3d8b8a2 | |||
e38ff99607 | |||
b0e3d922c8 | |||
a15bb8e994 | |||
6f487100cd | |||
0693a2315f | |||
f360e886ff | |||
6ea08cc5dc | |||
347c706d6f | |||
5f5e6616c7 | |||
657bcadc7e | |||
107666cc60 | |||
b37669184a | |||
163a01f224 | |||
3d58094199 | |||
463951a4f1 | |||
34804d5162 | |||
3895c33915 | |||
17f4eb1a56 | |||
0abdffdea6 | |||
d32999f178 | |||
f621feb843 | |||
8d277f029d | |||
1788a02338 | |||
ba0800d16c | |||
4008c7d8f6 | |||
610a2e2afc | |||
6f3715d1eb | |||
b78ecaa814 | |||
e6f5399d53 | |||
0e5806cadd | |||
68c9d4afa7 | |||
f0ea38fe49 | |||
b0332f923e | |||
8a76c25394 | |||
fd96126e3e | |||
ff3fbedc18 | |||
8791419f8e | |||
5447b247a0 | |||
aabbb10564 | |||
3ccd6c9a3e | |||
c290240de7 | |||
8e799b174b | |||
a9c3a93989 | |||
3ef8698f42 | |||
fa4e843c30 | |||
9a4d11f4d9 | |||
eed2b8d618 | |||
13f02c2aca | |||
d50f8fbc8b | |||
155238a516 | |||
427fcdbdca | |||
ca05d402a7 | |||
c5a80b68ca | |||
c1fb15b135 | |||
4b2c131836 | |||
9ca1e69b3c | |||
082d041d44 | |||
221f276c4b | |||
24cec21465 | |||
9f71ec6194 | |||
bb36afc390 | |||
b53bf0ff64 | |||
3ebc6f2436 | |||
2eef6778a6 | |||
81fabec810 | |||
dc6e7924b5 | |||
48dec5a2c8 | |||
9b500e1da9 | |||
a038820112 | |||
70a15973b6 | |||
09b6a00731 | |||
883c3cf0e9 | |||
a46bb8183c | |||
d5d5a7b012 | |||
a120efdc91 | |||
d48f4b06eb | |||
f078912736 | |||
63b0f0dedd | |||
84c22dbf5f | |||
b8cd1232be | |||
a518ab07f4 | |||
9e5a1ee975 | |||
95bf3f0316 | |||
d69dd513bc | |||
525cdf571a | |||
9cfe0a8804 | |||
50b54599ef | |||
ed6bef6d24 | |||
71268636df | |||
568729ecd6 | |||
9139725be6 | |||
969a8da6bf | |||
2338b26329 | |||
d4df206740 |
@ -14,7 +14,7 @@ IndentWidth: 4
|
|||||||
MaxEmptyLinesToKeep: 1
|
MaxEmptyLinesToKeep: 1
|
||||||
ObjCBlockIndentWidth: 4
|
ObjCBlockIndentWidth: 4
|
||||||
ObjCBreakBeforeNestedBlockParam: false
|
ObjCBreakBeforeNestedBlockParam: false
|
||||||
SortIncludes: false
|
SortIncludes: true
|
||||||
TabWidth: 4
|
TabWidth: 4
|
||||||
UseTab: Always
|
UseTab: Always
|
||||||
...
|
...
|
||||||
|
38
.gitea/workflows/build.yaml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
name: Build Tilde Friends
|
||||||
|
run-name: ${{ gitea.actor }} running 🚀
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Build-All:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
valid_volumes: ['/opt/keys']
|
||||||
|
volumes:
|
||||||
|
- /opt/keys:/opt/keys
|
||||||
|
steps:
|
||||||
|
- name: check out code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- run: ln -s /opt/keys .keys
|
||||||
|
- name: Setup JDK
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
java-version: '17'
|
||||||
|
distribution: 'temurin'
|
||||||
|
- name: Setup Android SDK
|
||||||
|
uses: android-actions/setup-android@v3
|
||||||
|
with:
|
||||||
|
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: ANDROID_SDK=$HOME/.android/sdk make -j`nproc` all docs
|
||||||
|
- run: docker build .
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
path: out/TildeFriends-release.fdroid.apk
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
path: out/winrelease/tildefriends.exe
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
path: out/tildefriends-x86_64.AppImage
|
9
.gitignore
vendored
@ -1,11 +1,18 @@
|
|||||||
|
build/
|
||||||
|
*.core
|
||||||
db.*
|
db.*
|
||||||
deps/ios_toolchain/
|
deps/ios_toolchain/
|
||||||
deps/openssl/
|
deps/openssl/
|
||||||
dist/
|
dist/
|
||||||
|
.flatpak-builder
|
||||||
.keys
|
.keys
|
||||||
|
logs/
|
||||||
**/node_modules
|
**/node_modules
|
||||||
out
|
out
|
||||||
|
repo/
|
||||||
|
result
|
||||||
*.swo
|
*.swo
|
||||||
*.swp
|
*.swp
|
||||||
|
tmp/
|
||||||
|
unsigned/
|
||||||
.zsign_cache/
|
.zsign_cache/
|
||||||
result
|
|
||||||
|
7
.gitmodules
vendored
@ -19,3 +19,10 @@
|
|||||||
[submodule "deps/picohttpparser"]
|
[submodule "deps/picohttpparser"]
|
||||||
path = deps/picohttpparser
|
path = deps/picohttpparser
|
||||||
url = https://github.com/h2o/picohttpparser.git
|
url = https://github.com/h2o/picohttpparser.git
|
||||||
|
[submodule "deps/openssl_src"]
|
||||||
|
path = deps/openssl_src
|
||||||
|
url = https://github.com/openssl/openssl.git
|
||||||
|
shallow = true
|
||||||
|
[submodule "deps/c-ares"]
|
||||||
|
path = deps/c-ares
|
||||||
|
url = https://github.com/c-ares/c-ares.git
|
||||||
|
349
GNUmakefile
@ -3,12 +3,14 @@
|
|||||||
MAKEFLAGS += --warn-undefined-variables
|
MAKEFLAGS += --warn-undefined-variables
|
||||||
MAKEFLAGS += --no-builtin-rules
|
MAKEFLAGS += --no-builtin-rules
|
||||||
|
|
||||||
VERSION_CODE := 20
|
VERSION_CODE := 30
|
||||||
VERSION_NUMBER := 0.0.20
|
VERSION_NUMBER := 0.0.25-wip
|
||||||
VERSION_NAME := They gave you a small cup.
|
VERSION_NAME := This program kills fascists.
|
||||||
|
|
||||||
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3460000.zip
|
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3470000.zip
|
||||||
LIBUV_URL := https://dist.libuv.org/dist/v1.48.0/libuv-v1.48.0.tar.gz
|
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
|
||||||
|
APPIMAGETOOL_MD5 := e989fadfc4d685fd3d6aeeb9b525d74d out/appimagetool
|
||||||
|
|
||||||
PROJECT = tildefriends
|
PROJECT = tildefriends
|
||||||
BUILD_DIR ?= out
|
BUILD_DIR ?= out
|
||||||
@ -16,9 +18,13 @@ UNAME_S := $(shell uname -s)
|
|||||||
UNAME_M := $(shell uname -m)
|
UNAME_M := $(shell uname -m)
|
||||||
|
|
||||||
ANDROID_SDK ?= ~/Android/Sdk
|
ANDROID_SDK ?= ~/Android/Sdk
|
||||||
|
BUNDLETOOL = out/bundletool.jar
|
||||||
|
|
||||||
HAVE_WIN := 0
|
HAVE_WIN := 0
|
||||||
|
|
||||||
|
export SOURCE_DATE_EPOCH=1
|
||||||
|
export TZ=UTC
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
ifeq ($(UNAME_S),Darwin)
|
||||||
BUILD_TYPES := macosdebug macosrelease iosdebug iosrelease iossimdebug iossimrelease
|
BUILD_TYPES := macosdebug macosrelease iosdebug iosrelease iossimdebug iossimrelease
|
||||||
else ifeq ($(UNAME_S),Linux)
|
else ifeq ($(UNAME_S),Linux)
|
||||||
@ -31,7 +37,8 @@ BUILD_TYPES := debug release
|
|||||||
CFLAGS += -Dstatic_assert=_Static_assert
|
CFLAGS += -Dstatic_assert=_Static_assert
|
||||||
LDFLAGS += \
|
LDFLAGS += \
|
||||||
-lbsd \
|
-lbsd \
|
||||||
-lnetwork
|
-lnetwork \
|
||||||
|
-Wno-stringop-overflow
|
||||||
else ifeq ($(UNAME_S),OpenBSD)
|
else ifeq ($(UNAME_S),OpenBSD)
|
||||||
BUILD_TYPES := debug release
|
BUILD_TYPES := debug release
|
||||||
CFLAGS += \
|
CFLAGS += \
|
||||||
@ -50,18 +57,23 @@ CFLAGS += \
|
|||||||
-Wall \
|
-Wall \
|
||||||
-Wextra \
|
-Wextra \
|
||||||
-Wno-unused-parameter \
|
-Wno-unused-parameter \
|
||||||
|
-Wno-unknown-warning-option \
|
||||||
-MMD \
|
-MMD \
|
||||||
-MP \
|
-MP \
|
||||||
-ffunction-sections \
|
-ffunction-sections \
|
||||||
-fdata-sections \
|
-fdata-sections \
|
||||||
-fno-exceptions \
|
-fno-exceptions \
|
||||||
-g
|
-g
|
||||||
|
LDFLAGS += \
|
||||||
|
-Wno-attributes \
|
||||||
|
-Wno-aggressive-loop-optimizations \
|
||||||
|
-flto=auto
|
||||||
|
|
||||||
ANDROID_MIN_SDK_VERSION := 24
|
ANDROID_MIN_SDK_VERSION := 24
|
||||||
ANDROID_TARGET_SDK_VERSION := 34
|
ANDROID_TARGET_SDK_VERSION := 34
|
||||||
ANDROID_BUILD_TOOLS := $(ANDROID_SDK)/build-tools/34.0.0
|
ANDROID_BUILD_TOOLS := $(ANDROID_SDK)/build-tools/34.0.0
|
||||||
ANDROID_PLATFORM := $(ANDROID_SDK)/platforms/android-$(ANDROID_TARGET_SDK_VERSION)
|
ANDROID_PLATFORM := $(ANDROID_SDK)/platforms/android-$(ANDROID_TARGET_SDK_VERSION)
|
||||||
ANDROID_NDK ?= $(ANDROID_SDK)/ndk/26.2.11394342
|
ANDROID_NDK ?= $(ANDROID_SDK)/ndk/26.3.11579264
|
||||||
|
|
||||||
ANDROID_ARMV7A_TARGETS := \
|
ANDROID_ARMV7A_TARGETS := \
|
||||||
out/androiddebug-armv7a/tildefriends \
|
out/androiddebug-armv7a/tildefriends \
|
||||||
@ -90,7 +102,7 @@ BUILD_TYPES += \
|
|||||||
androidrelease-x86 \
|
androidrelease-x86 \
|
||||||
androiddebug-x86_64 \
|
androiddebug-x86_64 \
|
||||||
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
|
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
|
||||||
|
|
||||||
WINDOWS_TARGETS := \
|
WINDOWS_TARGETS := \
|
||||||
@ -150,19 +162,26 @@ ANDROID_RELEASE_TARGETS := $(filter-out $(DEBUG_TARGETS),$(ANDROID_TARGETS))
|
|||||||
NONANDROID_RELEASE_TARGETS := $(filter-out $(ANDROID_ARM64_TARGETS),$(RELEASE_TARGETS))
|
NONANDROID_RELEASE_TARGETS := $(filter-out $(ANDROID_ARM64_TARGETS),$(RELEASE_TARGETS))
|
||||||
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))
|
||||||
|
ifneq ($(UNAME_S),OpenBSD)
|
||||||
|
$(NONMACOS_TARGETS): LDFLAGS += -static-libgcc
|
||||||
|
endif
|
||||||
|
|
||||||
$(NONANDROID_TARGETS): CFLAGS += -fno-omit-frame-pointer
|
$(NONANDROID_TARGETS): CFLAGS += -fno-omit-frame-pointer
|
||||||
$(filter-out $(ANDROID_TARGETS) $(WINDOWS_TARGETS),$(ALL_TARGETS)): LDFLAGS += -rdynamic
|
$(filter-out $(WINDOWS_TARGETS),$(ALL_TARGETS)): LDFLAGS += -rdynamic
|
||||||
$(ANDROID_TARGETS): CFLAGS += \
|
$(ANDROID_TARGETS): CFLAGS += \
|
||||||
--sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
|
--sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
|
||||||
-fPIC \
|
-fPIC \
|
||||||
-fdebug-compilation-dir . \
|
-fdebug-compilation-dir . \
|
||||||
-fomit-frame-pointer \
|
-fomit-frame-pointer \
|
||||||
-fno-asynchronous-unwind-tables \
|
-fno-asynchronous-unwind-tables \
|
||||||
-funwind-tables
|
-funwind-tables \
|
||||||
|
-Wno-unknown-warning-option
|
||||||
$(ANDROID_TARGETS): LDFLAGS += --sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC
|
$(ANDROID_TARGETS): LDFLAGS += --sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC
|
||||||
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
|
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
|
||||||
$(RELEASE_TARGETS): CFLAGS += -DNDEBUG
|
$(RELEASE_TARGETS): CFLAGS += \
|
||||||
|
-DNDEBUG \
|
||||||
|
-flto
|
||||||
$(NONANDROID_RELEASE_TARGETS): CFLAGS += -O3
|
$(NONANDROID_RELEASE_TARGETS): CFLAGS += -O3
|
||||||
$(ANDROID_RELEASE_TARGETS): CFLAGS += -Oz
|
$(ANDROID_RELEASE_TARGETS): CFLAGS += -Oz
|
||||||
$(WINDOWS_TARGETS): CC = x86_64-w64-mingw32-gcc-win32
|
$(WINDOWS_TARGETS): CC = x86_64-w64-mingw32-gcc-win32
|
||||||
@ -205,13 +224,16 @@ $(ANDROID_X86_TARGETS): LDFLAGS += -Ldeps/openssl/android/x86/usr/local/lib
|
|||||||
$(ANDROID_X86_64_TARGETS): CFLAGS += -Ideps/openssl/android/x86_64/usr/local/include
|
$(ANDROID_X86_64_TARGETS): CFLAGS += -Ideps/openssl/android/x86_64/usr/local/include
|
||||||
$(ANDROID_X86_64_TARGETS): LDFLAGS += -Ldeps/openssl/android/x86_64/usr/local/lib
|
$(ANDROID_X86_64_TARGETS): LDFLAGS += -Ldeps/openssl/android/x86_64/usr/local/lib
|
||||||
$(NONMACOS_TARGETS): CFLAGS += -Wno-cast-function-type
|
$(NONMACOS_TARGETS): CFLAGS += -Wno-cast-function-type
|
||||||
$(NONMACOS_TARGETS): LDFLAGS += -Wl,--gc-sections
|
$(DEADSTRIP_TARGETS): LDFLAGS += -Wl,--gc-sections
|
||||||
$(IOS_TARGETS): CFLAGS += -mios-version-min=9.0 -Ideps/openssl/ios/ios64-xcrun/usr/local/include
|
$(IOS_TARGETS): CFLAGS += -miphoneos-version-min=9.0 -Ideps/openssl/ios/ios64-xcrun/usr/local/include
|
||||||
$(IOS_TARGETS): LDFLAGS += -Ldeps/openssl/ios/ios64-xcrun/usr/local/lib
|
$(IOS_TARGETS): LDFLAGS += -miphoneos-version-min=9.0 -Ldeps/openssl/ios/ios64-xcrun/usr/local/lib
|
||||||
$(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/include
|
$(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/include
|
||||||
$(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
|
||||||
@ -238,6 +260,8 @@ APP_SOURCES_ios := $(wildcard src/*.m)
|
|||||||
APP_OBJS := $(call get_objs,APP_SOURCES)
|
APP_OBJS := $(call get_objs,APP_SOURCES)
|
||||||
$(APP_OBJS): CFLAGS += \
|
$(APP_OBJS): CFLAGS += \
|
||||||
-Ideps/base64c/include \
|
-Ideps/base64c/include \
|
||||||
|
-Ideps/c-ares/include \
|
||||||
|
-Ideps/c-ares_config \
|
||||||
-Ideps/crypt_blowfish \
|
-Ideps/crypt_blowfish \
|
||||||
-Ideps/libbacktrace \
|
-Ideps/libbacktrace \
|
||||||
-Ideps/libsodium \
|
-Ideps/libsodium \
|
||||||
@ -256,6 +280,108 @@ $(filter-out $(BUILD_DIR)/android% $(BUILD_DIR)/macos% $(BUILD_DIR)/ios%,$(APP_O
|
|||||||
-fanalyzer
|
-fanalyzer
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ARES_SOURCES := \
|
||||||
|
deps/c-ares/src/lib/ares_addrinfo2hostent.c \
|
||||||
|
deps/c-ares/src/lib/ares_addrinfo_localhost.c \
|
||||||
|
deps/c-ares/src/lib/ares_android.c \
|
||||||
|
deps/c-ares/src/lib/ares_cancel.c \
|
||||||
|
deps/c-ares/src/lib/ares_close_sockets.c \
|
||||||
|
deps/c-ares/src/lib/ares_conn.c \
|
||||||
|
deps/c-ares/src/lib/ares_cookie.c \
|
||||||
|
deps/c-ares/src/lib/ares_data.c \
|
||||||
|
deps/c-ares/src/lib/ares_destroy.c \
|
||||||
|
deps/c-ares/src/lib/ares_free_hostent.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_files.c \
|
||||||
|
deps/c-ares/src/lib/ares_sysconfig_mac.c \
|
||||||
|
deps/c-ares/src/lib/ares_sysconfig_win.c \
|
||||||
|
deps/c-ares/src/lib/ares_update_servers.c \
|
||||||
|
deps/c-ares/src/lib/ares_version.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_expand_name.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_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_ptr_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_parse_txt_reply.c \
|
||||||
|
deps/c-ares/src/lib/legacy/ares_parse_uri_reply.c \
|
||||||
|
deps/c-ares/src/lib/record/ares_dns_mapping.c \
|
||||||
|
deps/c-ares/src/lib/record/ares_dns_multistring.c \
|
||||||
|
deps/c-ares/src/lib/record/ares_dns_name.c \
|
||||||
|
deps/c-ares/src/lib/record/ares_dns_parse.c \
|
||||||
|
deps/c-ares/src/lib/record/ares_dns_record.c \
|
||||||
|
deps/c-ares/src/lib/record/ares_dns_write.c \
|
||||||
|
deps/c-ares/src/lib/str/ares_buf.c \
|
||||||
|
deps/c-ares/src/lib/str/ares_str.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/util/ares_math.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_timeval.c \
|
||||||
|
deps/c-ares/src/lib/util/ares_uri.c \
|
||||||
|
deps/c-ares/src/lib/windows_port.c \
|
||||||
|
deps/c-ares/src/lib/ares_timeout.c
|
||||||
|
ARES_OBJS := $(call get_objs,ARES_SOURCES)
|
||||||
|
$(ARES_OBJS): CFLAGS += \
|
||||||
|
-Ideps/c-ares/include \
|
||||||
|
-Ideps/c-ares/src/lib \
|
||||||
|
-Ideps/c-ares/src/lib/include \
|
||||||
|
-Ideps/c-ares_config/ \
|
||||||
|
-D_GNU_SOURCE \
|
||||||
|
-Wno-unused-function \
|
||||||
|
-Wno-deprecated-declarations \
|
||||||
|
-Wno-unused-result
|
||||||
|
|
||||||
BLOWFISH_SOURCES := \
|
BLOWFISH_SOURCES := \
|
||||||
deps/crypt_blowfish/crypt_blowfish.c \
|
deps/crypt_blowfish/crypt_blowfish.c \
|
||||||
deps/crypt_blowfish/crypt_gensalt.c \
|
deps/crypt_blowfish/crypt_gensalt.c \
|
||||||
@ -383,10 +509,17 @@ $(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
|
||||||
|
$(filter out/win%,$(UV_OBJS)): \
|
||||||
|
CFLAGS += \
|
||||||
|
-Wno-cast-function-type \
|
||||||
|
-Wno-missing-braces
|
||||||
ifeq ($(UNAME_S),Linux)
|
ifeq ($(UNAME_S),Linux)
|
||||||
$(UV_OBJS): CFLAGS += \
|
$(UV_OBJS): CFLAGS += \
|
||||||
-D_GNU_SOURCE
|
-D_GNU_SOURCE
|
||||||
@ -616,11 +749,12 @@ $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
|||||||
|
|
||||||
unix: debug release
|
unix: debug release
|
||||||
win: windebug winrelease
|
win: windebug winrelease
|
||||||
all: $(BUILD_TYPES) default.nix
|
all: $(BUILD_TYPES)
|
||||||
.PHONY: all win unix
|
.PHONY: all win unix
|
||||||
|
|
||||||
ALL_APP_OBJS := \
|
ALL_APP_OBJS := \
|
||||||
$(APP_OBJS) \
|
$(APP_OBJS) \
|
||||||
|
$(ARES_OBJS) \
|
||||||
$(BLOWFISH_OBJS) \
|
$(BLOWFISH_OBJS) \
|
||||||
$(LIBBACKTRACE_OBJS) \
|
$(LIBBACKTRACE_OBJS) \
|
||||||
$(MINIUNZIP_OBJS) \
|
$(MINIUNZIP_OBJS) \
|
||||||
@ -673,10 +807,6 @@ src/android/AndroidManifest.xml : $(firstword $(MAKEFILE_LIST))
|
|||||||
-e 's/android:targetSdkVersion="[[:digit:]]*"/android:targetSdkVersion="$(ANDROID_TARGET_SDK_VERSION)"/' \
|
-e 's/android:targetSdkVersion="[[:digit:]]*"/android:targetSdkVersion="$(ANDROID_TARGET_SDK_VERSION)"/' \
|
||||||
$@
|
$@
|
||||||
|
|
||||||
default.nix : $(firstword $(MAKEFILE_LIST))
|
|
||||||
@echo "[version] $@"
|
|
||||||
@sed -i -e 's/version = ".*";/version = "$(VERSION_NUMBER)";/' $@
|
|
||||||
|
|
||||||
# Android support.
|
# Android support.
|
||||||
out/res/layout_activity_main.xml.flat: src/android/res/layout/activity_main.xml
|
out/res/layout_activity_main.xml.flat: src/android/res/layout/activity_main.xml
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
@ -689,8 +819,25 @@ out/res/drawable_icon.xml.flat: src/android/res/drawable/icon.xml
|
|||||||
@$(ANDROID_BUILD_TOOLS)/aapt2 compile -o out/res/ src/android/res/drawable/icon.xml
|
@$(ANDROID_BUILD_TOOLS)/aapt2 compile -o out/res/ src/android/res/drawable/icon.xml
|
||||||
|
|
||||||
out/apk/res.apk out/gen/com/unprompted/tildefriends/R.java: out/res/layout_activity_main.xml.flat out/res/drawable_icon.xml.flat src/android/AndroidManifest.xml
|
out/apk/res.apk out/gen/com/unprompted/tildefriends/R.java: out/res/layout_activity_main.xml.flat out/res/drawable_icon.xml.flat src/android/AndroidManifest.xml
|
||||||
@mkdir -p $(dir $@)
|
@echo [aapt2 link] res.apk
|
||||||
@$(ANDROID_BUILD_TOOLS)/aapt2 link -I $(ANDROID_PLATFORM)/android.jar out/res/layout_activity_main.xml.flat out/res/drawable_icon.xml.flat --manifest src/android/AndroidManifest.xml -o out/apk/res.apk --java out/gen/
|
@mkdir -p out/apk/
|
||||||
|
@$(ANDROID_BUILD_TOOLS)/aapt2 link -I $(ANDROID_PLATFORM)/android.jar out/res/layout_activity_main.xml.flat out/res/drawable_icon.xml.flat \
|
||||||
|
--min-sdk-version $(ANDROID_MIN_SDK_VERSION) \
|
||||||
|
--target-sdk-version $(ANDROID_TARGET_SDK_VERSION) \
|
||||||
|
--manifest src/android/AndroidManifest.xml \
|
||||||
|
-o out/apk/res.apk \
|
||||||
|
--java out/gen/
|
||||||
|
|
||||||
|
out/apk/res.fdroid.apk out/gen_fdroid/com/unprompted/tildefriends/R.java: out/res/layout_activity_main.xml.flat out/res/drawable_icon.xml.flat src/android/AndroidManifest.xml
|
||||||
|
@echo [aapt2 link] res.fdroid.apk
|
||||||
|
@mkdir -p out/apk/
|
||||||
|
@$(ANDROID_BUILD_TOOLS)/aapt2 link -I $(ANDROID_PLATFORM)/android.jar out/res/layout_activity_main.xml.flat out/res/drawable_icon.xml.flat \
|
||||||
|
--min-sdk-version $(ANDROID_MIN_SDK_VERSION) \
|
||||||
|
--target-sdk-version $(ANDROID_TARGET_SDK_VERSION) \
|
||||||
|
--rename-manifest-package com.unprompted.tildefriends.fdroid \
|
||||||
|
--manifest src/android/AndroidManifest.xml \
|
||||||
|
-o out/apk/res.fdroid.apk \
|
||||||
|
--java out/gen_fdroid/
|
||||||
|
|
||||||
JAVA_FILES := out/gen/com/unprompted/tildefriends/R.java $(wildcard src/android/com/unprompted/tildefriends/*.java)
|
JAVA_FILES := out/gen/com/unprompted/tildefriends/R.java $(wildcard src/android/com/unprompted/tildefriends/*.java)
|
||||||
CLASS_FILES := $(foreach src,$(JAVA_FILES),out/classes/com/unprompted/tildefriends/$(notdir $(src:.java=.class)))
|
CLASS_FILES := $(foreach src,$(JAVA_FILES),out/classes/com/unprompted/tildefriends/$(notdir $(src:.java=.class)))
|
||||||
@ -702,7 +849,7 @@ $(CLASS_FILES) &: $(JAVA_FILES)
|
|||||||
out/apk/classes.dex: $(CLASS_FILES)
|
out/apk/classes.dex: $(CLASS_FILES)
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
@echo "[d8] $@"
|
@echo "[d8] $@"
|
||||||
@$(ANDROID_BUILD_TOOLS)/d8 --$(BUILD_TYPE) --lib $(ANDROID_PLATFORM)/android.jar --output $(dir $@) out/classes/com/unprompted/tildefriends/*.class
|
@$(ANDROID_BUILD_TOOLS)/d8 --lib $(ANDROID_PLATFORM)/android.jar --output $(dir $@) out/classes/com/unprompted/tildefriends/*.class
|
||||||
|
|
||||||
PACKAGE_DIRS := \
|
PACKAGE_DIRS := \
|
||||||
apps/ \
|
apps/ \
|
||||||
@ -711,25 +858,79 @@ PACKAGE_DIRS := \
|
|||||||
deps/prettier/ \
|
deps/prettier/ \
|
||||||
deps/lit/
|
deps/lit/
|
||||||
|
|
||||||
RAW_FILES := $(filter-out apps/blog% apps/issues% apps/welcome% apps/journal% %.map, $(shell find $(PACKAGE_DIRS) -type f))
|
RAW_FILES := $(sort $(filter-out apps/blog% apps/issues% apps/welcome% apps/journal% %.map, $(shell find $(PACKAGE_DIRS) -type f -not -name '.*')))
|
||||||
|
|
||||||
out/apk/TildeFriends-arm-debug.unsigned.apk: BUILD_TYPE := debug
|
out/apk/TildeFriends-arm-debug.unsigned.apk: BUILD_TYPE := debug
|
||||||
out/apk/TildeFriends-arm-release.unsigned.apk: BUILD_TYPE := release
|
out/apk/TildeFriends-arm-release.unsigned.apk: BUILD_TYPE := release
|
||||||
out/apk/TildeFriends-x86-debug.unsigned.apk: BUILD_TYPE := debug
|
out/apk/TildeFriends-x86-debug.unsigned.apk: BUILD_TYPE := debug
|
||||||
out/apk/TildeFriends-x86-release.unsigned.apk: BUILD_TYPE := release
|
out/apk/TildeFriends-x86-release.unsigned.apk: BUILD_TYPE := release
|
||||||
|
out/apk/TildeFriends-release.fdroid.unsigned.apk: BUILD_TYPE := release
|
||||||
|
|
||||||
out/apk/TildeFriends-arm-debug.unsigned.apk: out/apk/classes.dex out/androiddebug/tildefriends out/androiddebug-armv7a/tildefriends $(RAW_FILES) out/apk/res.apk
|
out/apk/TildeFriends-arm-debug.unsigned.apk: out/apk/classes.dex out/androiddebug/tildefriends out/androiddebug-armv7a/tildefriends $(RAW_FILES) out/apk/res.apk
|
||||||
out/apk/TildeFriends-arm-release.unsigned.apk: out/apk/classes.dex out/androidrelease/tildefriends out/androidrelease-armv7a/tildefriends $(RAW_FILES) out/apk/res.apk
|
out/apk/TildeFriends-arm-release.unsigned.apk: out/apk/classes.dex out/androidrelease/tildefriends out/androidrelease-armv7a/tildefriends $(RAW_FILES) out/apk/res.apk
|
||||||
out/apk/TildeFriends-x86-debug.unsigned.apk: out/apk/classes.dex out/androiddebug-x86_64/tildefriends out/androiddebug-x86/tildefriends $(RAW_FILES) out/apk/res.apk
|
out/apk/TildeFriends-x86-debug.unsigned.apk: out/apk/classes.dex out/androiddebug-x86_64/tildefriends out/androiddebug-x86/tildefriends $(RAW_FILES) out/apk/res.apk
|
||||||
out/apk/TildeFriends-x86-release.unsigned.apk: out/apk/classes.dex out/androidrelease-x86_64/tildefriends out/androidrelease-x86/tildefriends $(RAW_FILES) out/apk/res.apk
|
out/apk/TildeFriends-x86-release.unsigned.apk: out/apk/classes.dex out/androidrelease-x86_64/tildefriends out/androidrelease-x86/tildefriends $(RAW_FILES) out/apk/res.apk
|
||||||
|
out/apk/TildeFriends-release.fdroid.unsigned.apk: out/apk/classes.dex out/androidrelease/tildefriends out/androidrelease-armv7a/tildefriends out/androidrelease-x86_64/tildefriends out/androidrelease-x86/tildefriends $(RAW_FILES) out/apk/res.fdroid.apk
|
||||||
|
|
||||||
|
$(BUNDLETOOL):
|
||||||
|
@echo [curl] $(BUNDLETOOL_URL) TO $@
|
||||||
|
@curl -q -L --create-dirs -o $@ $(BUNDLETOOL_URL)
|
||||||
|
|
||||||
|
out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGETS)) $(RAW_FILES) out/apk/res.apk src/android/AndroidManifest.xml $(BUNDLETOOL)
|
||||||
|
@rm -rf out/aab/staging/
|
||||||
|
@mkdir -p out/aab/staging
|
||||||
|
@$(ANDROID_BUILD_TOOLS)/aapt2 link --proto-format -o out/aab/temporary.apk \
|
||||||
|
-I $(ANDROID_PLATFORM)/android.jar \
|
||||||
|
--min-sdk-version $(ANDROID_MIN_SDK_VERSION) \
|
||||||
|
--target-sdk-version $(ANDROID_TARGET_SDK_VERSION) \
|
||||||
|
--manifest src/android/AndroidManifest.xml \
|
||||||
|
-R out/res/layout_activity_main.xml.flat \
|
||||||
|
-R out/res/drawable_icon.xml.flat \
|
||||||
|
--auto-add-overlay
|
||||||
|
@unzip out/aab/temporary.apk -d out/aab/staging/
|
||||||
|
@mkdir -p out/aab/staging/root/deps
|
||||||
|
@mkdir -p out/aab/staging/classes
|
||||||
|
@mkdir -p out/aab/staging/dex
|
||||||
|
@mkdir -p out/aab/staging/manifest
|
||||||
|
@mv out/aab/staging/AndroidManifest.xml out/aab/staging/manifest/AndroidManifest.xml
|
||||||
|
@cp out/apk/classes.dex out/aab/staging/dex/
|
||||||
|
@rm -fv out/base.zip
|
||||||
|
@mkdir -p out/aab/staging/lib/arm64-v8a out/aab/staging/lib/armeabi-v7a out/aab/staging/lib/x86_64 out/aab/staging/lib/x86
|
||||||
|
@cp out/androidrelease/tildefriends out/aab/staging/lib/arm64-v8a/libtildefriends.so
|
||||||
|
@cp out/androidrelease-armv7a/tildefriends out/aab/staging/lib/armeabi-v7a/libtildefriends.so
|
||||||
|
@cp out/androidrelease-x86_64/tildefriends out/aab/staging/lib/x86_64/libtildefriends.so
|
||||||
|
@cp out/androidrelease-x86/tildefriends out/aab/staging/lib/x86/libtildefriends.so
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/arm64-v8a/libtildefriends.so
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/armeabi-v7a/libtildefriends.so
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/x86_64/libtildefriends.so
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/x86/libtildefriends.so
|
||||||
|
@cp -r apps/ out/aab/staging/root/
|
||||||
|
@rm -rf out/aab/staging/root/apps/welcome*
|
||||||
|
@cp -r core/ out/aab/staging/root/
|
||||||
|
@cp -r deps/prettier/ out/aab/staging/root/deps/
|
||||||
|
@cp -r deps/lit/ out/aab/staging/root/deps/
|
||||||
|
@cp -r deps/codemirror/ out/aab/staging/root/deps/
|
||||||
|
@cd out/aab/staging/; zip -r ../base.zip *; cd ../../../
|
||||||
|
@java -jar $(BUNDLETOOL) build-bundle --overwrite --config=src/android/BundleConfig.json --modules=out/aab/base.zip --output=$@
|
||||||
|
@jarsigner -keystore .keys/android.jks $@ androidKey -storepass android
|
||||||
|
|
||||||
|
aab: out/TildeFriends.aab
|
||||||
|
.PHONY: aab
|
||||||
|
|
||||||
|
out/TildeFriends.apks: out/TildeFriends.aab $(BUNDLETOOL)
|
||||||
|
@java -jar $(BUNDLETOOL) build-apks --bundle out/TildeFriends.aab --overwrite --output $@ --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android
|
||||||
|
|
||||||
|
aabgo: out/TildeFriends.apks $(BUNDLETOOL)
|
||||||
|
@java -jar $(BUNDLETOOL) install-apks --apks out/TildeFriends.apks
|
||||||
|
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
||||||
|
|
||||||
out/apk/TildeFriends-arm-%.unsigned.apk:
|
out/apk/TildeFriends-arm-%.unsigned.apk:
|
||||||
@mkdir -p $(dir $@) out/apk-arm-$(BUILD_TYPE)/lib/arm64-v8a/ out/apk-arm-$(BUILD_TYPE)/lib/armeabi-v7a/
|
@mkdir -p $(dir $@) out/apk-arm-$(BUILD_TYPE)/lib/arm64-v8a/ out/apk-arm-$(BUILD_TYPE)/lib/armeabi-v7a/
|
||||||
@echo "[aapt] $@"
|
@echo "[aapt] $@"
|
||||||
@cp out/android$(BUILD_TYPE)/tildefriends out/apk-arm-$(BUILD_TYPE)/lib/arm64-v8a/tildefriends.so
|
@cp out/android$(BUILD_TYPE)/tildefriends out/apk-arm-$(BUILD_TYPE)/lib/arm64-v8a/libtildefriends.so
|
||||||
@cp out/android$(BUILD_TYPE)-armv7a/tildefriends out/apk-arm-$(BUILD_TYPE)/lib/armeabi-v7a/tildefriends.so
|
@cp out/android$(BUILD_TYPE)-armv7a/tildefriends out/apk-arm-$(BUILD_TYPE)/lib/armeabi-v7a/libtildefriends.so
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-arm-$(BUILD_TYPE)/lib/arm64-v8a/tildefriends.so
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-arm-$(BUILD_TYPE)/lib/arm64-v8a/libtildefriends.so
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-arm-$(BUILD_TYPE)/lib/armeabi-v7a/tildefriends.so
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-arm-$(BUILD_TYPE)/lib/armeabi-v7a/libtildefriends.so
|
||||||
@cp out/apk/res.apk $@.zip
|
@cp out/apk/res.apk $@.zip
|
||||||
@cp out/apk/classes.dex out/apk-arm-$(BUILD_TYPE)/
|
@cp out/apk/classes.dex out/apk-arm-$(BUILD_TYPE)/
|
||||||
@cd out/apk-arm-$(BUILD_TYPE) && zip -u ../../$@.zip -q -9 -r . && cd ../../
|
@cd out/apk-arm-$(BUILD_TYPE) && zip -u ../../$@.zip -q -9 -r . && cd ../../
|
||||||
@ -739,16 +940,38 @@ out/apk/TildeFriends-arm-%.unsigned.apk:
|
|||||||
out/apk/TildeFriends-x86-%.unsigned.apk:
|
out/apk/TildeFriends-x86-%.unsigned.apk:
|
||||||
@mkdir -p $(dir $@) out/apk-x86-$(BUILD_TYPE)/lib/x86_64/ out/apk-x86-$(BUILD_TYPE)/lib/x86/
|
@mkdir -p $(dir $@) out/apk-x86-$(BUILD_TYPE)/lib/x86_64/ out/apk-x86-$(BUILD_TYPE)/lib/x86/
|
||||||
@echo "[aapt] $@"
|
@echo "[aapt] $@"
|
||||||
@cp out/android$(BUILD_TYPE)-x86_64/tildefriends out/apk-x86-$(BUILD_TYPE)/lib/x86_64/tildefriends.so
|
@cp out/android$(BUILD_TYPE)-x86_64/tildefriends out/apk-x86-$(BUILD_TYPE)/lib/x86_64/libtildefriends.so
|
||||||
@cp out/android$(BUILD_TYPE)-x86/tildefriends out/apk-x86-$(BUILD_TYPE)/lib/x86/tildefriends.so
|
@cp out/android$(BUILD_TYPE)-x86/tildefriends out/apk-x86-$(BUILD_TYPE)/lib/x86/libtildefriends.so
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-x86-$(BUILD_TYPE)/lib/x86_64/tildefriends.so
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-x86-$(BUILD_TYPE)/lib/x86_64/libtildefriends.so
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-x86-$(BUILD_TYPE)/lib/x86/tildefriends.so
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-x86-$(BUILD_TYPE)/lib/x86/libtildefriends.so
|
||||||
@cp out/apk/res.apk $@.zip
|
@cp out/apk/res.apk $@.zip
|
||||||
@cp out/apk/classes.dex out/apk-x86-$(BUILD_TYPE)/
|
@cp out/apk/classes.dex out/apk-x86-$(BUILD_TYPE)/
|
||||||
@cd out/apk-x86-$(BUILD_TYPE) && zip -u ../../$@.zip -q -9 -r . && cd ../../
|
@cd out/apk-x86-$(BUILD_TYPE) && zip -u ../../$@.zip -q -9 -r . && cd ../../
|
||||||
@zip -u $@.zip -q -9 $(RAW_FILES)
|
@zip -u $@.zip -q -9 $(RAW_FILES)
|
||||||
@$(ANDROID_BUILD_TOOLS)/zipalign -f 4 $@.zip $@
|
@$(ANDROID_BUILD_TOOLS)/zipalign -f 4 $@.zip $@
|
||||||
|
|
||||||
|
out/apk/TildeFriends-%.fdroid.unsigned.apk:
|
||||||
|
@rm -rf out/apk-fdroid-$(BUILD_TYPE) out/apk-fdroid-$(BUILD_TYPE)-raw
|
||||||
|
@mkdir -p $(dir $@) out/apk-fdroid-$(BUILD_TYPE)/lib/x86_64/ out/apk-fdroid-$(BUILD_TYPE)/lib/x86/ out/apk-fdroid-$(BUILD_TYPE)/lib/arm64-v8a/ out/apk-fdroid-$(BUILD_TYPE)/lib/armeabi-v7a/
|
||||||
|
@echo "[aapt] $@"
|
||||||
|
@cp out/android$(BUILD_TYPE)-x86_64/tildefriends out/apk-fdroid-$(BUILD_TYPE)/lib/x86_64/libtildefriends.so
|
||||||
|
@cp out/android$(BUILD_TYPE)-x86/tildefriends out/apk-fdroid-$(BUILD_TYPE)/lib/x86/libtildefriends.so
|
||||||
|
@cp out/android$(BUILD_TYPE)/tildefriends out/apk-fdroid-$(BUILD_TYPE)/lib/arm64-v8a/libtildefriends.so
|
||||||
|
@cp out/android$(BUILD_TYPE)-armv7a/tildefriends out/apk-fdroid-$(BUILD_TYPE)/lib/armeabi-v7a/libtildefriends.so
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-fdroid-$(BUILD_TYPE)/lib/x86_64/libtildefriends.so
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-fdroid-$(BUILD_TYPE)/lib/x86/libtildefriends.so
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-fdroid-$(BUILD_TYPE)/lib/arm64-v8a/libtildefriends.so
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-fdroid-$(BUILD_TYPE)/lib/armeabi-v7a/libtildefriends.so
|
||||||
|
@cp out/apk/res.fdroid.apk $@.zip
|
||||||
|
@cp out/apk/classes.dex out/apk-fdroid-$(BUILD_TYPE)/classes.dex
|
||||||
|
@touch -d @0 out/apk-fdroid-$(BUILD_TYPE)/classes.dex out/apk-fdroid-$(BUILD_TYPE)/lib/*/libtildefriends.so
|
||||||
|
@chmod 755 out/apk-fdroid-$(BUILD_TYPE)/classes.dex out/apk-fdroid-$(BUILD_TYPE)/lib/*/libtildefriends.so
|
||||||
|
@cd out/apk-fdroid-$(BUILD_TYPE) && zip -X -u ../../$@.zip -q classes.dex lib/*/libtildefriends.so && cd ../../
|
||||||
|
@mkdir out/apk-fdroid-$(BUILD_TYPE)-raw
|
||||||
|
@for i in $(RAW_FILES); do mkdir -p $$(dirname out/apk-fdroid-$(BUILD_TYPE)-raw/$$i) && cp $$i out/apk-fdroid-$(BUILD_TYPE)-raw/$$i && touch -d @0 out/apk-fdroid-$(BUILD_TYPE)-raw/$$i && chmod 644 out/apk-fdroid-$(BUILD_TYPE)-raw/$$i; done
|
||||||
|
@cd out/apk-fdroid-$(BUILD_TYPE)-raw && zip -X -u ../../$@.zip -q $(RAW_FILES) && cd ../../
|
||||||
|
@$(ANDROID_BUILD_TOOLS)/zipalign -f 4 $@.zip $@
|
||||||
|
|
||||||
out/%.apk: out/apk/%.unsigned.apk
|
out/%.apk: out/apk/%.unsigned.apk
|
||||||
@echo "[apksigner] $(notdir $@)"
|
@echo "[apksigner] $(notdir $@)"
|
||||||
@$(ANDROID_BUILD_TOOLS)/apksigner sign --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android --key-pass pass:android --min-sdk-version $(ANDROID_MIN_SDK_VERSION) --out $@ $<
|
@$(ANDROID_BUILD_TOOLS)/apksigner sign --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android --key-pass pass:android --min-sdk-version $(ANDROID_MIN_SDK_VERSION) --out $@ $<
|
||||||
@ -761,6 +984,11 @@ out/%.zopfli.apk: out/%.apk
|
|||||||
release-apk: out/TildeFriends-arm-release.zopfli.apk out/TildeFriends-x86-release.zopfli.apk
|
release-apk: out/TildeFriends-arm-release.zopfli.apk out/TildeFriends-x86-release.zopfli.apk
|
||||||
.PHONY: release-apk
|
.PHONY: release-apk
|
||||||
|
|
||||||
|
apkgo: out/TildeFriends-arm-debug.apk
|
||||||
|
@adb install -r $<
|
||||||
|
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
||||||
|
.PHONY: apkgo
|
||||||
|
|
||||||
releaseapkgo: out/TildeFriends-arm-release.apk
|
releaseapkgo: out/TildeFriends-arm-release.apk
|
||||||
@adb install -r $<
|
@adb install -r $<
|
||||||
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
||||||
@ -780,6 +1008,7 @@ 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
|
||||||
@ -824,10 +1053,6 @@ apklog:
|
|||||||
.PHONY: apklog
|
.PHONY: apklog
|
||||||
|
|
||||||
fetchdeps:
|
fetchdeps:
|
||||||
@echo "[fetch] libuv"
|
|
||||||
@test -f out/deps/libuv.tar.gz && test "$$(cat out/deps/libuv.txt 2>/dev/null)" = $(LIBUV_URL) || (mkdir -p out/deps/ && curl -q $(LIBUV_URL) -o out/deps/libuv.tar.gz)
|
|
||||||
@test -d deps/libuv/ && test "$$(cat out/deps/libuv.txt 2>/dev/null)" = $(LIBUV_URL) || (rm -rf deps/libuv/ && mkdir -p deps/libuv/ && tar -C deps/libuv/ -m --strip=1 -xf out/deps/libuv.tar.gz)
|
|
||||||
@echo -n $(LIBUV_URL) > out/deps/libuv.txt
|
|
||||||
@echo "[fetch] sqlite"
|
@echo "[fetch] sqlite"
|
||||||
@test -f out/deps/sqlite.zip && test "$$(cat out/deps/sqlite.txt 2>/dev/null)" = $(SQLITE_URL) || (mkdir -p out/deps/ && curl -q $(SQLITE_URL) -o out/deps/sqlite.zip)
|
@test -f out/deps/sqlite.zip && test "$$(cat out/deps/sqlite.txt 2>/dev/null)" = $(SQLITE_URL) || (mkdir -p out/deps/ && curl -q $(SQLITE_URL) -o out/deps/sqlite.zip)
|
||||||
@test -d deps/sqlite/ && test "$$(cat out/deps/sqlite.txt 2>/dev/null)" = $(SQLITE_URL) || (mkdir -p deps/sqlite/ && unzip -qDjo -d deps/sqlite/ out/deps/sqlite.zip)
|
@test -d deps/sqlite/ && test "$$(cat out/deps/sqlite.txt 2>/dev/null)" = $(SQLITE_URL) || (mkdir -p deps/sqlite/ && unzip -qDjo -d deps/sqlite/ out/deps/sqlite.zip)
|
||||||
@ -841,7 +1066,7 @@ fetchdeps:
|
|||||||
|
|
||||||
ANDROID_DEPS := deps/openssl/android/arm64-v8a/usr/local/lib/libssl.a
|
ANDROID_DEPS := deps/openssl/android/arm64-v8a/usr/local/lib/libssl.a
|
||||||
$(ANDROID_DEPS):
|
$(ANDROID_DEPS):
|
||||||
+@tools/ssl-android
|
+@ANDROID_NDK_ROOT=$(ANDROID_NDK) tools/ssl-android
|
||||||
$(filter $(BUILD_DIR)/android%,$(APP_OBJS)): | $(ANDROID_DEPS)
|
$(filter $(BUILD_DIR)/android%,$(APP_OBJS)): | $(ANDROID_DEPS)
|
||||||
|
|
||||||
ifeq ($(HAVE_WIN),1)
|
ifeq ($(HAVE_WIN),1)
|
||||||
@ -858,14 +1083,41 @@ $(IOS_DEPS):
|
|||||||
$(filter $(BUILD_DIR)/ios%,$(APP_OBJS)): | $(IOS_DEPS)
|
$(filter $(BUILD_DIR)/ios%,$(APP_OBJS)): | $(IOS_DEPS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
out/tildefriends-x86_64.AppImage: out/release/tildefriends out/data.zip
|
||||||
|
@echo "[appimage] $$@"
|
||||||
|
@rm -rf out/tildefriends.AppDir
|
||||||
|
@mkdir -p out/tildefriends.AppDir/usr/bin
|
||||||
|
@mkdir -p out/tildefriends.AppDir/usr/share/applications
|
||||||
|
@mkdir -p out/tildefriends.AppDir/usr/share/icons/hicolor/scalable/apps
|
||||||
|
@mkdir -p out/tildefriends.AppDir/usr/share/tildefriends
|
||||||
|
@echo $(APPIMAGETOOL_MD5) > out/appimagetool.md5
|
||||||
|
@test -x out/appimagetool || curl -q -L -o out/appimagetool $(APPIMAGETOOL_URL) && md5sum -c out/appimagetool.md5 && chmod +x out/appimagetool
|
||||||
|
@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
|
||||||
|
@cp src/ios/tildefriends.svg out/tildefriends.AppDir/usr/share/icons/hicolor/scalable/apps/
|
||||||
|
@cp src/ios/tildefriends.svg out/tildefriends.AppDir/
|
||||||
|
@cp out/release/tildefriends out/tildefriends.AppDir/usr/bin/
|
||||||
|
@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
|
||||||
|
.PHONY: appimage
|
||||||
|
|
||||||
|
flatpak: out/
|
||||||
|
flatpak-builder --force-clean --user --install-deps-from=flathub --install --repo=out/flatpak-repo out/flatpak src/com.unprompted.tildefriends.yml
|
||||||
|
flatpak build-bundle out/flatpak-repo out/tildefriends.flatpak com.unprompted.tildefriends
|
||||||
|
.PHONY: flatpak
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_DIR)
|
rm -rf $(BUILD_DIR)
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
||||||
dist: release-apk iosrelease-ipa $(if $(HAVE_WIN), out/winrelease/tildefriends.standalone.exe) default.nix
|
tarball:
|
||||||
@echo [archive] dist/tildefriends-$(VERSION_NUMBER).tar.xz
|
@echo [archive] out/tildefriends-$(VERSION_NUMBER).tar.xz
|
||||||
@rm -rf out/tildefriends-$(VERSION_NUMBER)
|
@rm -rf out/tildefriends-$(VERSION_NUMBER)
|
||||||
@mkdir -p dist/ out/tildefriends-$(VERSION_NUMBER)
|
@mkdir -p out/tildefriends-$(VERSION_NUMBER)
|
||||||
@git ls-files --recurse-submodules | tar -c -T- | tar -x -C out/tildefriends-$(VERSION_NUMBER)
|
@git ls-files --recurse-submodules | tar -c -T- | tar -x -C out/tildefriends-$(VERSION_NUMBER)
|
||||||
@tar \
|
@tar \
|
||||||
--exclude=apps/welcome* \
|
--exclude=apps/welcome* \
|
||||||
@ -882,9 +1134,15 @@ dist: release-apk iosrelease-ipa $(if $(HAVE_WIN), out/winrelease/tildefriends.s
|
|||||||
--exclude=deps/sqlite/shell.c \
|
--exclude=deps/sqlite/shell.c \
|
||||||
--exclude=deps/zlib/contrib/vstudio \
|
--exclude=deps/zlib/contrib/vstudio \
|
||||||
--exclude=deps/zlib/doc \
|
--exclude=deps/zlib/doc \
|
||||||
-caf dist/tildefriends-$(VERSION_NUMBER).tar.xz \
|
-caf out/tildefriends-$(VERSION_NUMBER).tar.xz \
|
||||||
-C out/ \
|
-C out/ \
|
||||||
tildefriends-$(VERSION_NUMBER)
|
tildefriends-$(VERSION_NUMBER)
|
||||||
|
.PHONY: tarball
|
||||||
|
|
||||||
|
dist: release-apk iosrelease-ipa aab $(if $(HAVE_WIN), out/winrelease/tildefriends.standalone.exe) out/TildeFriends-release.fdroid.apk appimage tarball
|
||||||
|
@mkdir -p dist/
|
||||||
|
@echo "[cp] tildefriends-$(VERSION_NUMBER).tar.xz"
|
||||||
|
@cp out/tildefriends-$(VERSION_NUMBER).tar.xz dist/tildefriends-$(VERSION_NUMBER).tar.xz
|
||||||
@echo "[cp] TildeFriends-x86-$(VERSION_NUMBER).apk"
|
@echo "[cp] TildeFriends-x86-$(VERSION_NUMBER).apk"
|
||||||
@cp out/TildeFriends-x86-release.zopfli.apk dist/TildeFriends-x86-$(VERSION_NUMBER).apk
|
@cp out/TildeFriends-x86-release.zopfli.apk dist/TildeFriends-x86-$(VERSION_NUMBER).apk
|
||||||
@echo "[cp] TildeFriends-arm-$(VERSION_NUMBER).apk"
|
@echo "[cp] TildeFriends-arm-$(VERSION_NUMBER).apk"
|
||||||
@ -893,6 +1151,12 @@ dist: release-apk iosrelease-ipa $(if $(HAVE_WIN), out/winrelease/tildefriends.s
|
|||||||
@cp out/tildefriends-release.ipa dist/TildeFriends-$(VERSION_NUMBER).ipa
|
@cp out/tildefriends-release.ipa dist/TildeFriends-$(VERSION_NUMBER).ipa
|
||||||
@test $(HAVE_WIN) && echo "[cp] tildefriends-$(VERSION_NUMBER).exe"
|
@test $(HAVE_WIN) && echo "[cp] tildefriends-$(VERSION_NUMBER).exe"
|
||||||
@test $(HAVE_WIN) && cp out/winrelease/tildefriends.standalone.exe dist/tildefriends-$(VERSION_NUMBER).exe
|
@test $(HAVE_WIN) && cp out/winrelease/tildefriends.standalone.exe dist/tildefriends-$(VERSION_NUMBER).exe
|
||||||
|
@echo "[cp] TildeFriends-$(VERSION_NUMBER).aab"
|
||||||
|
@cp out/TildeFriends.aab dist/TildeFriends-$(VERSION_NUMBER).aab
|
||||||
|
@echo "[cp] TildeFriends-$(VERSION_NUMBER).fdroid.apk"
|
||||||
|
@cp out/TildeFriends-release.fdroid.apk dist/TildeFriends-$(VERSION_NUMBER).fdroid.apk
|
||||||
|
@echo "[cp] TildeFriends-x86_64-$(VERSION_NUMBER).AppImage"
|
||||||
|
@cp out/tildefriends-x86_64.AppImage dist/TildeFriends-x86_64-$(VERSION_NUMBER).AppImage
|
||||||
.PHONY: dist
|
.PHONY: dist
|
||||||
|
|
||||||
dist-test: dist
|
dist-test: dist
|
||||||
@ -913,3 +1177,6 @@ prettier:
|
|||||||
docs:
|
docs:
|
||||||
@doxygen
|
@doxygen
|
||||||
.PHONY: docs
|
.PHONY: docs
|
||||||
|
|
||||||
|
fdroid: out/apk/TildeFriends-release.fdroid.unsigned.apk
|
||||||
|
.PHONY: fdroid
|
||||||
|
20
README.md
@ -19,8 +19,24 @@ 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.
|
||||||
|
|
||||||
1. Requires openssl (`libssl-dev`, in debian-speak). All other dependencies
|
Tilde Friends uses git submodules, so either:
|
||||||
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
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🎛",
|
"emoji": "🎛",
|
||||||
"previous": "&vrpS/vE7n588iYv1p8HafDxHB+YDHTrtUbJiu9nGA9I=.sha256"
|
"previous": "&R49FywYF8CXPhoSEydLbSCgvCddeyTiBwGuDU/gqY+M=.sha256"
|
||||||
}
|
}
|
||||||
|
@ -27,23 +27,30 @@ function global_settings_set(key, value) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function title_case(name) {
|
||||||
|
return name
|
||||||
|
.split('_')
|
||||||
|
.map((x) => x.charAt(0).toUpperCase() + x.substring(1))
|
||||||
|
.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
window.addEventListener('load', function () {
|
window.addEventListener('load', function () {
|
||||||
const permission_template = (permission) => html` <code>${permission}</code>`;
|
const permission_template = (permission) => html` <code>${permission}</code>`;
|
||||||
function input_template(key, description) {
|
function input_template(key, description) {
|
||||||
if (description.type === 'boolean') {
|
if (description.type === 'boolean') {
|
||||||
return html`
|
return html`
|
||||||
<li class="w3-row">
|
<li class="w3-row">
|
||||||
<label class="w3-quarter" for=${'gs_' + key} style="font-weight: bold">${key}</label>
|
<label class="w3-quarter" for=${'gs_' + key} style="font-weight: bold">${title_case(key)}</label>
|
||||||
<div class="w3-quarter w3-padding">${description.description}</div>
|
<div class="w3-quarter w3-padding">${description.description}</div>
|
||||||
<input class="w3-quarter w3-check" type="checkbox" ?checked=${description.value} id=${'gs_' + key}></input>
|
<div class="w3-quarter w3-padding w3-center"><input class="w3-check" type="checkbox" ?checked=${description.value} id=${'gs_' + key}></input></div>
|
||||||
<button class="w3-quarter w3-button w3-theme-action" @click=${(e) => global_settings_set(key, e.srcElement.previousElementSibling.checked)}>Set</button>
|
<button class="w3-quarter w3-button w3-theme-action" @click=${(e) => global_settings_set(key, e.srcElement.previousElementSibling.firstChild.checked)}>Set</button>
|
||||||
</li>
|
</li>
|
||||||
`;
|
`;
|
||||||
} else if (description.type === 'textarea') {
|
} else if (description.type === 'textarea') {
|
||||||
return html`
|
return html`
|
||||||
<li class="w3-row">
|
<li class="w3-row">
|
||||||
<label class="w3-quarter" for=${'gs_' + key} style="font-weight: bold"
|
<label class="w3-quarter" for=${'gs_' + key} style="font-weight: bold"
|
||||||
>${key}</label
|
>${title_case(key)}</label
|
||||||
>
|
>
|
||||||
<div class="w3-rest w3-padding">${description.description}</div>
|
<div class="w3-rest w3-padding">${description.description}</div>
|
||||||
<textarea
|
<textarea
|
||||||
@ -68,7 +75,7 @@ ${description.value}</textarea
|
|||||||
} else {
|
} else {
|
||||||
return html`
|
return html`
|
||||||
<li class="w3-row">
|
<li class="w3-row">
|
||||||
<label class="w3-quarter" for=${'gs_' + key} style="font-weight: bold">${key}</label>
|
<label class="w3-quarter" for=${'gs_' + key} style="font-weight: bold">${title_case(key)}</label>
|
||||||
<div class="w3-quarter w3-padding">${description.description}</div>
|
<div class="w3-quarter w3-padding">${description.description}</div>
|
||||||
<input class="w3-input w3-quarter" type="text" value="${description.value}" id=${'gs_' + key}></input>
|
<input class="w3-input w3-quarter" type="text" value="${description.value}" id=${'gs_' + key}></input>
|
||||||
<button class="w3-button w3-quarter w3-theme-action" @click=${(e) => global_settings_set(key, e.srcElement.previousElementSibling.value)}>Set</button>
|
<button class="w3-button w3-quarter w3-theme-action" @click=${(e) => global_settings_set(key, e.srcElement.previousElementSibling.value)}>Set</button>
|
||||||
|
2
apps/blog/commonmark.min.js
vendored
42
apps/blog/lit-all.min.js
vendored
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "💽"
|
"emoji": "💽",
|
||||||
|
"previous": "&uQzkIe/Aj8yNhLKe3hEq+5fEJsGwIUx8NVBjJKwoV2U=.sha256"
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,19 @@ async function key_list(db) {
|
|||||||
app.setDocument(doc);
|
app.setDocument(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function load() {
|
||||||
|
if (core.user?.credentials?.session) {
|
||||||
|
database_list();
|
||||||
|
} else {
|
||||||
|
app.setDocument(`<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body style="background: #888">
|
||||||
|
<h1>Must be signed in to examine databases.</h1>
|
||||||
|
</body>
|
||||||
|
</html>`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
core.register('message', async function (message) {
|
core.register('message', async function (message) {
|
||||||
if (message.event == 'hashChange') {
|
if (message.event == 'hashChange') {
|
||||||
let hash = message.hash.substring(1);
|
let hash = message.hash.substring(1);
|
||||||
@ -62,9 +75,9 @@ core.register('message', async function (message) {
|
|||||||
} else if (hash.length) {
|
} else if (hash.length) {
|
||||||
key_list(await database(hash.split(':').slice(1).join(':')));
|
key_list(await database(hash.split(':').slice(1).join(':')));
|
||||||
} else {
|
} else {
|
||||||
database_list();
|
load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
database_list();
|
load();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🪪",
|
"emoji": "🪪",
|
||||||
"previous": "&de7q4A59auHP/34bXgeNH05JZoxsGr5TjwXPvehWH30=.sha256"
|
"previous": "&5kw/2PgcySwOYCmAkjHTR2xTkIx3i7UjQmtQ8MfgWw8=.sha256"
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
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));
|
||||||
});
|
});
|
||||||
@ -15,9 +17,13 @@ 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();
|
||||||
|
let server_id = await ssb.getServerIdentity();
|
||||||
await app.setDocument(
|
await app.setDocument(
|
||||||
`
|
`
|
||||||
<head>
|
<head>
|
||||||
@ -98,6 +104,16 @@ 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">
|
||||||
@ -116,14 +132,15 @@ 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>
|
||||||
${id}
|
${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>' : ''}
|
||||||
</li>`
|
</li>`
|
||||||
)
|
)
|
||||||
.join('\n') +
|
.join('\n') +
|
||||||
|
2
apps/issues/commonmark.min.js
vendored
42
apps/issues/lit-all.min.js
vendored
2
apps/journal/commonmark.min.js
vendored
42
apps/journal/lit-all.min.js
vendored
42
apps/sneaker/lit-all.min.js
vendored
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🐌",
|
"emoji": "🐌",
|
||||||
"previous": "&TqpkOAi38Oi6gW6guh95KIvWY2M/vjBE8NLLNHK+M00=.sha256"
|
"previous": "&0ZjcRFTyAmJMm3qhqKy5Ffrue23G1CAUfc1i2WYZrzQ=.sha256"
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,9 @@ 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
42
apps/ssb/lit-all.min.js
vendored
@ -67,7 +67,7 @@ class TfElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_hash(hash) {
|
set_hash(hash) {
|
||||||
this.hash = hash || '#';
|
this.hash = decodeURIComponent(hash || '#');
|
||||||
if (this.hash.startsWith('#q=')) {
|
if (this.hash.startsWith('#q=')) {
|
||||||
this.tab = 'search';
|
this.tab = 'search';
|
||||||
} else if (this.hash === '#connections') {
|
} else if (this.hash === '#connections') {
|
||||||
|
@ -180,6 +180,13 @@ class TfComposeElement extends LitElement {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
document.execCommand(
|
||||||
|
'insertText',
|
||||||
|
false,
|
||||||
|
event.clipboardData.getData('text/plain')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
@ -538,7 +545,7 @@ class TfComposeElement extends LitElement {
|
|||||||
id="edit"
|
id="edit"
|
||||||
@input=${this.input}
|
@input=${this.input}
|
||||||
@paste=${this.paste}
|
@paste=${this.paste}
|
||||||
contenteditable
|
contenteditable="plaintext-only"
|
||||||
.innerText=${live(draft.text ?? '')}
|
.innerText=${live(draft.text ?? '')}
|
||||||
></span>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -73,18 +73,23 @@ class TfMessageElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.message?.votes?.length) {
|
if (this.message?.votes?.length) {
|
||||||
return html`<div class="w3-button" @click=${this.show_reactions}>
|
return html` <div class="w3-container">
|
||||||
|
<div
|
||||||
|
class="w3-button w3-bar w3-padding-small"
|
||||||
|
@click=${this.show_reactions}
|
||||||
|
>
|
||||||
${(this.message.votes || []).map(
|
${(this.message.votes || []).map(
|
||||||
(vote) => html`
|
(vote) => html`
|
||||||
<span
|
<span
|
||||||
title="${this.users[vote.author]?.name ?? vote.author} ${new Date(
|
class="w3-bar-item w3-padding-small"
|
||||||
vote.timestamp
|
title="${this.users[vote.author]?.name ??
|
||||||
)}"
|
vote.author} ${new Date(vote.timestamp)}"
|
||||||
>
|
>
|
||||||
${normalize_expression(vote.content.vote.expression)}
|
${normalize_expression(vote.content.vote.expression)}
|
||||||
</span>
|
</span>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,6 +188,10 @@ class TfProfileElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copy_id() {
|
||||||
|
navigator.clipboard.writeText(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (
|
if (
|
||||||
this.id == this.whoami &&
|
this.id == this.whoami &&
|
||||||
@ -285,8 +289,10 @@ class TfProfileElement extends LitElement {
|
|||||||
typeof profile.image == 'string' ? profile.image : profile.image?.link;
|
typeof profile.image == 'string' ? profile.image : profile.image?.link;
|
||||||
image = this.editing?.image ?? image;
|
image = this.editing?.image ?? image;
|
||||||
let description = this.editing?.description ?? profile.description;
|
let description = this.editing?.description ?? profile.description;
|
||||||
return html`<div style="border: 2px solid black; background-color: rgba(255, 255, 255, 0.2); padding: 16px">
|
return html`<div class="w3-container" style="box-sizing: border-box; border: 2px solid black; background-color: rgba(255, 255, 255, 0.2)">
|
||||||
<tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)})
|
<p><tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)})
|
||||||
|
<input type="text" class="w3-input w3-border w3-theme-d1" readonly value=${this.id}></input>
|
||||||
|
<button class="w3-button w3-theme-d1 w3-ripple" @click=${this.copy_id}>Copy</button>
|
||||||
<div style="display: flex; flex-direction: row; gap: 1em">
|
<div style="display: flex; flex-direction: row; gap: 1em">
|
||||||
${edit_profile}
|
${edit_profile}
|
||||||
<div style="flex: 1 0 50%">
|
<div style="flex: 1 0 50%">
|
||||||
@ -300,11 +306,11 @@ class TfProfileElement extends LitElement {
|
|||||||
Blocking ${profile.blocking} identities.
|
Blocking ${profile.blocking} identities.
|
||||||
Blocked by ${profile.blocked} identities.
|
Blocked by ${profile.blocked} identities.
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<p>
|
||||||
${edit}
|
${edit}
|
||||||
${follow}
|
${follow}
|
||||||
${block}
|
${block}
|
||||||
</div>
|
</p>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,12 @@ 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>
|
||||||
|
@ -17,6 +17,12 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
|
|
||||||
static styles = styles;
|
static styles = styles;
|
||||||
|
|
||||||
|
static k_broadcast_emojis = {
|
||||||
|
discovery: '🏓',
|
||||||
|
room: '🚪',
|
||||||
|
peer_exchange: '🕸',
|
||||||
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
let self = this;
|
let self = this;
|
||||||
@ -92,6 +98,7 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
Connect
|
Connect
|
||||||
</button>
|
</button>
|
||||||
<div class="w3-bar-item">
|
<div class="w3-bar-item">
|
||||||
|
${TfTabConnectionsElement.k_broadcast_emojis[connection.origin]}
|
||||||
<tf-user id=${connection.pubkey} .users=${this.users}></tf-user>
|
<tf-user id=${connection.pubkey} .users=${this.users}></tf-user>
|
||||||
${this.render_connection_summary(connection)}
|
${this.render_connection_summary(connection)}
|
||||||
</div>
|
</div>
|
||||||
@ -122,6 +129,7 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
</button>
|
</button>
|
||||||
|
${connection.flags.one_shot ? '🔃' : undefined}
|
||||||
<tf-user id=${connection.id} .users=${this.users}></tf-user>
|
<tf-user id=${connection.id} .users=${this.users}></tf-user>
|
||||||
${connection.tunnel !== undefined
|
${connection.tunnel !== undefined
|
||||||
? '🚇'
|
? '🚇'
|
||||||
@ -129,7 +137,9 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
<div>
|
<div>
|
||||||
${requests.map(
|
${requests.map(
|
||||||
(x) => html`
|
(x) => html`
|
||||||
<span class="w3-tag w3-small"
|
<span
|
||||||
|
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"
|
||||||
@ -149,10 +159,20 @@ 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
|
||||||
|
@ -5,6 +5,7 @@ import {styles} from './tf-styles.js';
|
|||||||
class TfTabSearchElement extends LitElement {
|
class TfTabSearchElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
|
drafts: {type: Object},
|
||||||
whoami: {type: String},
|
whoami: {type: String},
|
||||||
users: {type: Object},
|
users: {type: Object},
|
||||||
following: {type: Array},
|
following: {type: Array},
|
||||||
@ -22,6 +23,10 @@ class TfTabSearchElement extends LitElement {
|
|||||||
this.users = {};
|
this.users = {};
|
||||||
this.following = [];
|
this.following = [];
|
||||||
this.expanded = {};
|
this.expanded = {};
|
||||||
|
this.drafts = {};
|
||||||
|
tfrpc.rpc.localStorageGet('drafts').then(function (d) {
|
||||||
|
self.drafts = JSON.parse(d || '{}');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async search(query) {
|
async search(query) {
|
||||||
@ -70,6 +75,18 @@ class TfTabSearchElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
draft(event) {
|
||||||
|
let id = event.detail.id || '';
|
||||||
|
let previous = this.drafts[id];
|
||||||
|
if (event.detail.draft !== undefined) {
|
||||||
|
this.drafts[id] = event.detail.draft;
|
||||||
|
} else {
|
||||||
|
delete this.drafts[id];
|
||||||
|
}
|
||||||
|
this.drafts = Object.assign({}, this.drafts);
|
||||||
|
tfrpc.rpc.localStorageSet('drafts', JSON.stringify(this.drafts));
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.query !== this.last_query) {
|
if (this.query !== this.last_query) {
|
||||||
this.last_query = this.query;
|
this.last_query = this.query;
|
||||||
@ -81,7 +98,7 @@ class TfTabSearchElement extends LitElement {
|
|||||||
<input type="text" class="w3-input w3-theme-d1" id="search" value=${this.query} style="flex: 1" @keydown=${this.search_keydown}></input>
|
<input type="text" class="w3-input w3-theme-d1" id="search" value=${this.query} style="flex: 1" @keydown=${this.search_keydown}></input>
|
||||||
<button class="w3-button w3-theme-d1" @click=${(event) => self.search(self.renderRoot.getElementById('search').value)}>Search</button>
|
<button class="w3-button w3-theme-d1" @click=${(event) => self.search(self.renderRoot.getElementById('search').value)}>Search</button>
|
||||||
</div>
|
</div>
|
||||||
<tf-news id="news" whoami=${this.whoami} .messages=${this.messages} .users=${this.users} .expanded=${this.expanded} @tf-expand=${this.on_expand}></tf-news>
|
<tf-news id="news" whoami=${this.whoami} .messages=${this.messages} .users=${this.users} .expanded=${this.expanded} .drafts=${this.drafts} @tf-expand=${this.on_expand} @tf-draft=${this.draft}></tf-news>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"
|
style="width: 2em; height: 2em; vertical-align: middle; object-fit: cover"
|
||||||
src="/${image_link}/view"
|
src="/${image_link}/view"
|
||||||
/>`;
|
/>`;
|
||||||
}
|
}
|
||||||
|
4
apps/test.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"type": "tildefriends-app",
|
||||||
|
"emoji": "📦"
|
||||||
|
}
|
3
apps/test/app.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
app.setDocument(
|
||||||
|
'<p style="color: #fff">Maybe one day this app will run tests, but for now there is nothing to see here.</p>'
|
||||||
|
);
|
1
apps/test/hello.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Hello, world!
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "👋",
|
"emoji": "👋",
|
||||||
"previous": "&W5aJp2DgOW5rQ0AOIC9Ut3DpsahPrO6PjkJ1PQbNRdM=.sha256"
|
"previous": "&7gFmLW5zSMhmxWWY1+jeRcHdullgujSqGJg94lVgr1k=.sha256"
|
||||||
}
|
}
|
||||||
|
78
apps/welcome/appimage.svg
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?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>
|
After Width: | Height: | Size: 19 KiB |
75
apps/welcome/f-droid.svg
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?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="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">
|
||||||
|
<defs id="defs4232">
|
||||||
|
<linearGradient inkscape:collect="always" id="linearGradient5212">
|
||||||
|
<stop style="stop-color:#ffffff;stop-opacity:0.09803922" offset="0" id="stop5214"/>
|
||||||
|
<stop style="stop-color:#ffffff;stop-opacity:0" offset="1" id="stop5216"/>
|
||||||
|
</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"/>
|
||||||
|
<filter inkscape:collect="always" style="color-interpolation-filters:sRGB" id="filter4175" x="-0.023846937" width="1.0476939" y="-0.02415504" height="1.0483101">
|
||||||
|
<feGaussianBlur inkscape:collect="always" stdDeviation="0.45053152" id="feGaussianBlur4177"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<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"/>
|
||||||
|
<metadata id="metadata4235">
|
||||||
|
<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: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 id="g4955">
|
||||||
|
<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 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"/>
|
||||||
|
<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 transform="translate(42,0)" id="g4967">
|
||||||
|
<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"/>
|
||||||
|
<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"/>
|
||||||
|
<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"/>
|
||||||
|
<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"/>
|
||||||
|
</g>
|
||||||
|
<g id="g4979">
|
||||||
|
<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"/>
|
||||||
|
<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"/>
|
||||||
|
<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"/>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(0,1013.3622)" id="g4211">
|
||||||
|
<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"/>
|
||||||
|
<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"/>
|
||||||
|
</g>
|
||||||
|
<g id="g4989" transform="translate(0,0.50001738)">
|
||||||
|
<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"/>
|
||||||
|
<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"/>
|
||||||
|
</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>
|
||||||
|
<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>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 21 KiB |
23
apps/welcome/googleplay.svg
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?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>
|
After Width: | Height: | Size: 1.8 KiB |
@ -66,8 +66,30 @@
|
|||||||
<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> Code</a
|
><i class="fa fa-mug-hot"></i> Development</a
|
||||||
>
|
>
|
||||||
|
<p>
|
||||||
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<div class="w3-col l4 m6">
|
<div class="w3-col l4 m6">
|
||||||
<img src="tildefriends.png" class="w3-image w3-right w3-hide-small" />
|
<img src="tildefriends.png" class="w3-image w3-right w3-hide-small" />
|
||||||
@ -88,36 +110,31 @@
|
|||||||
<a href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
<a href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
||||||
>Download</a
|
>Download</a
|
||||||
>
|
>
|
||||||
Tilde Friends and run your own instance, or use
|
Tilde Friends 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>
|
<li>Create an account to identify yourself with that instance.</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. You will automatically discover peers on the
|
Connect to others.
|
||||||
same instance and same network if there are any. Or use
|
<ul>
|
||||||
<a href="https://github.com/staltz/ssb-room/blob/master/FAQ.md"
|
<li>Automatically discover peers on the same network.</li>
|
||||||
>rooms</a
|
<li>
|
||||||
>
|
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
|
||||||
>
|
>.
|
||||||
operates as a room, so you can connect and see who else is online
|
</li>
|
||||||
and establish a connection.
|
<li>
|
||||||
|
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>
|
||||||
@ -206,8 +223,13 @@
|
|||||||
|
|
||||||
<!-- 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>Trusted Technology</b></h1>
|
<h1 class="w3-jumbo"><b>Boring Technology</b></h1>
|
||||||
<p>Tilde Friends is built using boring, trusted tech.</p>
|
<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.
|
||||||
@ -244,7 +266,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://www.openssl.org/" class="w3-col s3">
|
<a href="https://github.com/openssl/openssl/releases" 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>
|
||||||
@ -270,6 +292,13 @@
|
|||||||
<i class="fa fa-fire w3-text-cyan w3-jumbo"></i>
|
<i class="fa fa-fire w3-text-cyan w3-jumbo"></i>
|
||||||
<p>Lit</p>
|
<p>Lit</p>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://github.com/c-ares/c-ares" class="w3-col s3">
|
||||||
|
<i class="fa fa-book-atlas w3-text-purple w3-jumbo"></i>
|
||||||
|
<p>c-ares</p>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w3-row" style="margin-top: 64px">
|
||||||
<a href="https://www.gnu.org/software/make/" class="w3-col s3">
|
<a href="https://www.gnu.org/software/make/" class="w3-col s3">
|
||||||
<i class="fa fa-hammer w3-text-teal w3-jumbo"></i>
|
<i class="fa fa-hammer w3-text-teal w3-jumbo"></i>
|
||||||
<p>GNU Make</p>
|
<p>GNU Make</p>
|
||||||
|
2
apps/wiki/commonmark.min.js
vendored
42
apps/wiki/lit-all.min.js
vendored
12
core/app.js
@ -10,7 +10,7 @@ let gSessionIndex = 0;
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function makeSessionId() {
|
function makeSessionId() {
|
||||||
return (gSessionIndex++).toString();
|
return 'session_' + (gSessionIndex++).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -172,11 +172,7 @@ async function socket(request, response, client) {
|
|||||||
0x1
|
0x1
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
process = await core.getSessionProcessBlob(
|
process = await core.getProcessBlob(blobId, sessionId, options);
|
||||||
blobId,
|
|
||||||
sessionId,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (process) {
|
if (process) {
|
||||||
@ -211,10 +207,6 @@ async function socket(request, response, client) {
|
|||||||
if (process && process.timeout > 0) {
|
if (process && process.timeout > 0) {
|
||||||
setTimeout(ping, process.timeout);
|
setTimeout(ping, process.timeout);
|
||||||
}
|
}
|
||||||
} else if (message.action == 'enableStats') {
|
|
||||||
if (process) {
|
|
||||||
core.enableStats(process, message.enabled);
|
|
||||||
}
|
|
||||||
} else if (message.action == 'resetPermission') {
|
} else if (message.action == 'resetPermission') {
|
||||||
if (process) {
|
if (process) {
|
||||||
process.resetPermission(message.permission);
|
process.resetPermission(message.permission);
|
||||||
|
@ -162,6 +162,7 @@ class TfNavigationElement extends LitElement {
|
|||||||
class="w3-dropdown-content w3-bar-block w3-card-4"
|
class="w3-dropdown-content w3-bar-block w3-card-4"
|
||||||
style="max-width: 100%; right: 0"
|
style="max-width: 100%; right: 0"
|
||||||
>
|
>
|
||||||
|
<div style="position: fixed; left: 0; right: 0; top: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.25); z-index: -100" @click=${self.toggle_id_dropdown}></div>
|
||||||
<button
|
<button
|
||||||
class="w3-bar-item w3-button w3-border"
|
class="w3-bar-item w3-button w3-border"
|
||||||
@click=${() => (window.location.href = '/~core/identity')}
|
@click=${() => (window.location.href = '/~core/identity')}
|
||||||
@ -382,8 +383,8 @@ class TfNavigationElement extends LitElement {
|
|||||||
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
||||||
<div class="w3-model w3-animate-top" style="position: absolute; left: 50%; transform: translate(-50%); z-index: 1">
|
<div class="w3-model w3-animate-top" style="position: absolute; left: 50%; transform: translate(-50%); z-index: 1">
|
||||||
<dijv class="w3-modal-content w3-card-4" style="display: block; padding: 1em">
|
<dijv class="w3-modal-content w3-card-4" style="display: block; padding: 1em">
|
||||||
<span @click=${self.clear_error} class="w3-button w3-display-topright">×</span>
|
<span id="close_error" @click=${self.clear_error} class="w3-button w3-display-topright">×</span>
|
||||||
<div style="color: ${this.status.color ?? kErrorColor}"><b>ERROR:</b><p style="white-space: pre">${this.status.message}</p></div>
|
<div style="color: ${this.status.color ?? kErrorColor}"><b>ERROR:</b><p id="error" style="white-space: pre">${this.status.message}</p></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@ -1190,6 +1191,7 @@ function api_requestPermission(permission, id) {
|
|||||||
check.classList.add('w3-check');
|
check.classList.add('w3-check');
|
||||||
check.classList.add('w3-blue');
|
check.classList.add('w3-blue');
|
||||||
div.appendChild(check);
|
div.appendChild(check);
|
||||||
|
div.appendChild(document.createTextNode(' '));
|
||||||
let label = document.createElement('label');
|
let label = document.createElement('label');
|
||||||
label.htmlFor = check.id;
|
label.htmlFor = check.id;
|
||||||
label.appendChild(document.createTextNode('Remember this decision.'));
|
label.appendChild(document.createTextNode('Remember this decision.'));
|
||||||
@ -1274,7 +1276,6 @@ function _receive_websocket_message(message) {
|
|||||||
document.getElementById('viewPane').style.display = message.edit_only
|
document.getElementById('viewPane').style.display = message.edit_only
|
||||||
? 'none'
|
? 'none'
|
||||||
: 'flex';
|
: 'flex';
|
||||||
send({action: 'enableStats', enabled: true});
|
|
||||||
} else if (message && message.action == 'ping') {
|
} else if (message && message.action == 'ping') {
|
||||||
send({action: 'pong'});
|
send({action: 'pong'});
|
||||||
} else if (message && message.action == 'stats') {
|
} else if (message && message.action == 'stats') {
|
||||||
@ -1783,10 +1784,11 @@ 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: 'babel',
|
parser: gCurrentFile?.toLowerCase()?.endsWith('.html') ? 'html' : 'babel',
|
||||||
plugins: [babel, estree],
|
plugins: [babel, estree, prettier_html],
|
||||||
trailingComma: 'es5',
|
trailingComma: 'es5',
|
||||||
useTabs: true,
|
useTabs: true,
|
||||||
semi: true,
|
semi: true,
|
||||||
@ -1821,8 +1823,8 @@ function toggleVisibleWhitespace() {
|
|||||||
.cm-highlightTab {
|
.cm-highlightTab {
|
||||||
background-image: unset !important;
|
background-image: unset !important;
|
||||||
}
|
}
|
||||||
.cm-highlightSpace:before {
|
.cm-highlightSpace {
|
||||||
content: unset !important;
|
background-image: unset !important;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
window.localStorage.setItem('visible_whitespace', '1');
|
window.localStorage.setItem('visible_whitespace', '1');
|
||||||
|
749
core/core.js
@ -4,76 +4,6 @@ import * as http from './http.js';
|
|||||||
|
|
||||||
let gProcesses = {};
|
let gProcesses = {};
|
||||||
let gStatsTimer = false;
|
let gStatsTimer = false;
|
||||||
|
|
||||||
const k_content_security_policy =
|
|
||||||
'sandbox allow-downloads allow-top-navigation-by-user-activation';
|
|
||||||
|
|
||||||
let k_static_files = [
|
|
||||||
{uri: '/', path: 'index.html', type: 'text/html; charset=UTF-8'},
|
|
||||||
];
|
|
||||||
|
|
||||||
const k_global_settings = {
|
|
||||||
index: {
|
|
||||||
type: 'string',
|
|
||||||
default_value: '/~core/apps/',
|
|
||||||
description: 'Default path.',
|
|
||||||
},
|
|
||||||
index_map: {
|
|
||||||
type: 'textarea',
|
|
||||||
default_value: undefined,
|
|
||||||
description:
|
|
||||||
'Mappings from hostname to redirect path, one per line, as in: "www.tildefriends.net=/~core/index/"',
|
|
||||||
},
|
|
||||||
room: {
|
|
||||||
type: 'boolean',
|
|
||||||
default_value: true,
|
|
||||||
description: 'Whether this instance should behave as a room.',
|
|
||||||
},
|
|
||||||
room_name: {
|
|
||||||
type: 'string',
|
|
||||||
default_value: 'tilde friends tunnel',
|
|
||||||
description: 'Name of the room.',
|
|
||||||
},
|
|
||||||
code_of_conduct: {
|
|
||||||
type: 'textarea',
|
|
||||||
default_value: undefined,
|
|
||||||
description: 'Code of conduct presented at sign-in.',
|
|
||||||
},
|
|
||||||
http_redirect: {
|
|
||||||
type: 'string',
|
|
||||||
default_value: undefined,
|
|
||||||
description:
|
|
||||||
'If connecting by HTTP and HTTPS is configured, Location header prefix (ie, "https://example.com")',
|
|
||||||
},
|
|
||||||
fetch_hosts: {
|
|
||||||
type: 'string',
|
|
||||||
default_value: undefined,
|
|
||||||
description:
|
|
||||||
'Comma-separated list of host names to which HTTP fetch requests are allowed. None if empty.',
|
|
||||||
},
|
|
||||||
blob_fetch_age_seconds: {
|
|
||||||
type: 'integer',
|
|
||||||
default_value:
|
|
||||||
platform() == 'android' || platform() == 'iphone'
|
|
||||||
? 0.5 * 365 * 24 * 60 * 60
|
|
||||||
: undefined,
|
|
||||||
description:
|
|
||||||
'Only blobs mentioned more recently than this age will be automatically fetched.',
|
|
||||||
},
|
|
||||||
blob_expire_age_seconds: {
|
|
||||||
type: 'integer',
|
|
||||||
default_value:
|
|
||||||
platform() == 'android' || platform() == 'iphone'
|
|
||||||
? 1.0 * 365 * 24 * 60 * 60
|
|
||||||
: undefined,
|
|
||||||
description: 'Blobs older than this will be automatically deleted.',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let gGlobalSettings = {
|
|
||||||
index: '/~core/apps/',
|
|
||||||
};
|
|
||||||
|
|
||||||
let kPingInterval = 60 * 1000;
|
let kPingInterval = 60 * 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,23 +175,6 @@ 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
|
||||||
@ -289,8 +202,7 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
}
|
}
|
||||||
process.lastActive = Date.now();
|
process.lastActive = Date.now();
|
||||||
process.lastPing = null;
|
process.lastPing = null;
|
||||||
process.timeout = options.timeout;
|
process.timeout = kPingInterval;
|
||||||
process.stats = false;
|
|
||||||
process.ready = new Promise(function (resolve, reject) {
|
process.ready = new Promise(function (resolve, reject) {
|
||||||
resolveReady = resolve;
|
resolveReady = resolve;
|
||||||
rejectReady = reject;
|
rejectReady = reject;
|
||||||
@ -329,59 +241,59 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
permissionsGranted: function () {
|
permissionsGranted: async 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 &&
|
||||||
gGlobalSettings.userPermissions &&
|
settings.userPermissions &&
|
||||||
gGlobalSettings.userPermissions[user] &&
|
settings.userPermissions[user] &&
|
||||||
gGlobalSettings.userPermissions[user][options.packageOwner]
|
settings.userPermissions[user][options.packageOwner]
|
||||||
) {
|
) {
|
||||||
return gGlobalSettings.userPermissions[user][
|
return settings.userPermissions[user][options.packageOwner][
|
||||||
options.packageOwner
|
options.packageName
|
||||||
][options.packageName];
|
];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
allPermissionsGranted: function () {
|
allPermissionsGranted: async 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 &&
|
||||||
gGlobalSettings.userPermissions &&
|
settings.userPermissions &&
|
||||||
gGlobalSettings.userPermissions[user]
|
settings.userPermissions[user]
|
||||||
) {
|
) {
|
||||||
return gGlobalSettings.userPermissions[user];
|
return settings.userPermissions[user];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
permissionsForUser: function (user) {
|
permissionsForUser: async function (user) {
|
||||||
return (
|
let settings = await loadSettings();
|
||||||
(gGlobalSettings?.permissions
|
return settings?.permissions?.[user] ?? [];
|
||||||
? gGlobalSettings.permissions[user]
|
|
||||||
: []) ?? []
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
apps: (user) => getApps(user, process),
|
apps: (user) => getApps(user, process),
|
||||||
getSockets: getSockets,
|
getSockets: getSockets,
|
||||||
permissionTest: function (permission) {
|
permissionTest: async 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 (
|
||||||
gGlobalSettings.userPermissions &&
|
settings.userPermissions &&
|
||||||
gGlobalSettings.userPermissions[user] &&
|
settings.userPermissions[user] &&
|
||||||
gGlobalSettings.userPermissions[user][options.packageOwner] &&
|
settings.userPermissions[user][options.packageOwner] &&
|
||||||
gGlobalSettings.userPermissions[user][options.packageOwner][
|
settings.userPermissions[user][options.packageOwner][
|
||||||
options.packageName
|
options.packageName
|
||||||
] &&
|
] &&
|
||||||
gGlobalSettings.userPermissions[user][options.packageOwner][
|
settings.userPermissions[user][options.packageOwner][
|
||||||
options.packageName
|
options.packageName
|
||||||
][permission] !== undefined
|
][permission] !== undefined
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
gGlobalSettings.userPermissions[user][options.packageOwner][
|
settings.userPermissions[user][options.packageOwner][
|
||||||
options.packageName
|
options.packageName
|
||||||
][permission]
|
][permission]
|
||||||
) {
|
) {
|
||||||
@ -392,9 +304,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(function (value) {
|
.then(async function (value) {
|
||||||
if (value == 'allow') {
|
if (value == 'allow') {
|
||||||
storePermission(
|
await ssb.setUserPermission(
|
||||||
user,
|
user,
|
||||||
options.packageOwner,
|
options.packageOwner,
|
||||||
options.packageName,
|
options.packageName,
|
||||||
@ -406,7 +318,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') {
|
||||||
storePermission(
|
await ssb.setUserPermission(
|
||||||
user,
|
user,
|
||||||
options.packageOwner,
|
options.packageOwner,
|
||||||
options.packageName,
|
options.packageName,
|
||||||
@ -493,22 +405,24 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (process.credentials?.permissions?.administration) {
|
if (process.credentials?.permissions?.administration) {
|
||||||
imports.core.globalSettingsDescriptions = function () {
|
imports.core.globalSettingsDescriptions = async function () {
|
||||||
let settings = Object.assign({}, k_global_settings);
|
let settings = Object.assign({}, defaultGlobalSettings());
|
||||||
for (let [key, value] of Object.entries(gGlobalSettings)) {
|
for (let [key, value] of Object.entries(await loadSettings())) {
|
||||||
if (settings[key]) {
|
if (settings[key]) {
|
||||||
settings[key].value = value;
|
settings[key].value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return settings;
|
return settings;
|
||||||
};
|
};
|
||||||
imports.core.globalSettingsGet = function (key) {
|
imports.core.globalSettingsGet = async function (key) {
|
||||||
return gGlobalSettings[key];
|
let settings = await loadSettings();
|
||||||
|
return settings?.[key];
|
||||||
};
|
};
|
||||||
imports.core.globalSettingsSet = function (key, value) {
|
imports.core.globalSettingsSet = async function (key, value) {
|
||||||
print('Setting', key, value);
|
print('Setting', key, value);
|
||||||
gGlobalSettings[key] = value;
|
let settings = await loadSettings();
|
||||||
setGlobalSettings(gGlobalSettings);
|
settings[key] = value;
|
||||||
|
await new Database('core').set('settings', JSON.stringify(settings));
|
||||||
print('Done.');
|
print('Done.');
|
||||||
};
|
};
|
||||||
imports.core.deleteUser = async function (user) {
|
imports.core.deleteUser = async function (user) {
|
||||||
@ -675,11 +589,24 @@ 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 = function (url, options) {
|
imports.fetch = async function (url, options) {
|
||||||
return http.fetch(url, options, gGlobalSettings.fetch_hosts);
|
let settings = await loadSettings();
|
||||||
|
return http.fetch(url, options, settings?.fetch_hosts);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -706,12 +633,12 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
Object.keys(db).map((x) => [x, db[x].bind(db)])
|
Object.keys(db).map((x) => [x, db[x].bind(db)])
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
imports.databases = function () {
|
imports.databases = async function () {
|
||||||
return [].concat(
|
return [].concat(
|
||||||
databases.list(
|
await databases.list(
|
||||||
':shared:' + process.credentials.session.name + ':%'
|
':shared:' + process.credentials.session.name + ':%'
|
||||||
),
|
),
|
||||||
databases.list(process.credentials.session.name + ':%')
|
await databases.list(process.credentials.session.name + ':%')
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -730,22 +657,22 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
process.sendPermissions = function sendPermissions() {
|
process.sendPermissions = async function sendPermissions() {
|
||||||
process.app.send({
|
process.app.send({
|
||||||
action: 'permissions',
|
action: 'permissions',
|
||||||
permissions: imports.core.permissionsGranted(),
|
permissions: await imports.core.permissionsGranted(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
process.resetPermission = function resetPermission(permission) {
|
process.resetPermission = async function resetPermission(permission) {
|
||||||
let user = process?.credentials?.session?.name;
|
let user = process?.credentials?.session?.name;
|
||||||
storePermission(
|
await ssb.setUserPermission(
|
||||||
user,
|
user,
|
||||||
options?.packageOwner,
|
options?.packageOwner,
|
||||||
options?.packageName,
|
options?.packageName,
|
||||||
permission,
|
permission,
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
process.sendPermissions();
|
return process.sendPermissions();
|
||||||
};
|
};
|
||||||
process.task.setImports(imports);
|
process.task.setImports(imports);
|
||||||
process.task.activate();
|
process.task.activate();
|
||||||
@ -778,10 +705,14 @@ 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()});
|
||||||
process.sendPermissions();
|
await process.sendPermissions();
|
||||||
}
|
}
|
||||||
await process.task.execute({name: appSourceName, source: appSource});
|
await process.task.execute({name: appSourceName, source: appSource});
|
||||||
resolveReady(process);
|
resolveReady(process);
|
||||||
|
if (!gStatsTimer) {
|
||||||
|
gStatsTimer = true;
|
||||||
|
sendStats();
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (process.app) {
|
if (process.app) {
|
||||||
if (process?.task?.onError) {
|
if (process?.task?.onError) {
|
||||||
@ -798,402 +729,6 @@ 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
|
|
||||||
* @param {*} response
|
|
||||||
* @param {*} data
|
|
||||||
* @param {*} type
|
|
||||||
* @param {*} headers
|
|
||||||
* @param {*} status_code
|
|
||||||
*/
|
|
||||||
function sendData(response, data, type, headers, status_code) {
|
|
||||||
if (data) {
|
|
||||||
response.writeHead(
|
|
||||||
status_code ?? 200,
|
|
||||||
Object.assign(
|
|
||||||
{
|
|
||||||
'Content-Type':
|
|
||||||
type ||
|
|
||||||
httpd.mime_type_from_magic_bytes(data) ||
|
|
||||||
'application/binary',
|
|
||||||
'Content-Length': data.byteLength,
|
|
||||||
},
|
|
||||||
headers || {}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
response.end(data);
|
|
||||||
} else {
|
|
||||||
response.writeHead(
|
|
||||||
status_code ?? 404,
|
|
||||||
Object.assign(
|
|
||||||
{
|
|
||||||
'Content-Type': 'text/plain; charset=utf-8',
|
|
||||||
'Content-Length': 'File not found'.length,
|
|
||||||
},
|
|
||||||
headers || {}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
response.end('File not found');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let g_handler_index = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODOC
|
|
||||||
* @param {*} response
|
|
||||||
* @param {*} handler_blob_id
|
|
||||||
* @param {*} path
|
|
||||||
* @param {*} query
|
|
||||||
* @param {*} headers
|
|
||||||
* @param {*} packageOwner
|
|
||||||
* @param {*} packageName
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async function useAppHandler(
|
|
||||||
response,
|
|
||||||
handler_blob_id,
|
|
||||||
path,
|
|
||||||
query,
|
|
||||||
headers,
|
|
||||||
packageOwner,
|
|
||||||
packageName
|
|
||||||
) {
|
|
||||||
print('useAppHandler', packageOwner, packageName);
|
|
||||||
let do_resolve;
|
|
||||||
let promise = new Promise(async function (resolve, reject) {
|
|
||||||
do_resolve = resolve;
|
|
||||||
});
|
|
||||||
let process;
|
|
||||||
let result;
|
|
||||||
try {
|
|
||||||
process = await getProcessBlob(
|
|
||||||
handler_blob_id,
|
|
||||||
'handler_' + g_handler_index++,
|
|
||||||
{
|
|
||||||
script: 'handler.js',
|
|
||||||
imports: {
|
|
||||||
request: {
|
|
||||||
path: path,
|
|
||||||
query: query,
|
|
||||||
},
|
|
||||||
respond: do_resolve,
|
|
||||||
},
|
|
||||||
credentials: await httpd.auth_query(headers),
|
|
||||||
packageOwner: packageOwner,
|
|
||||||
packageName: packageName,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
await process.ready;
|
|
||||||
|
|
||||||
result = await promise;
|
|
||||||
} finally {
|
|
||||||
if (process?.task) {
|
|
||||||
await process.task.kill();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODOC
|
|
||||||
* @param {*} request
|
|
||||||
* @param {*} response
|
|
||||||
* @param {*} blobId
|
|
||||||
* @param {*} uri
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async function blobHandler(request, response, blobId, uri) {
|
|
||||||
// TODO(tasiaiso): break this down ?
|
|
||||||
for (let i in k_static_files) {
|
|
||||||
if (uri === k_static_files[i].uri && k_static_files[i].path) {
|
|
||||||
let stat = await File.stat('core/' + k_static_files[i].path);
|
|
||||||
let id = `${stat.mtime}_${stat.size}`;
|
|
||||||
|
|
||||||
if (request.headers['if-none-match'] === '"' + id + '"') {
|
|
||||||
response.writeHead(304, {'Content-Length': '0'});
|
|
||||||
response.end();
|
|
||||||
} else {
|
|
||||||
let data = await File.readFile('core/' + k_static_files[i].path);
|
|
||||||
response.writeHead(
|
|
||||||
200,
|
|
||||||
Object.assign(
|
|
||||||
{
|
|
||||||
'Content-Type': k_static_files[i].type,
|
|
||||||
'Content-Length': data.byteLength,
|
|
||||||
etag: '"' + id + '"',
|
|
||||||
},
|
|
||||||
k_static_files[i].headers || {}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
response.end(data);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!uri) {
|
|
||||||
response.writeHead(303, {
|
|
||||||
Location:
|
|
||||||
(request.client.tls ? 'https://' : 'http://') +
|
|
||||||
(request.headers['x-forwarded-host'] ?? request.headers.host) +
|
|
||||||
blobId +
|
|
||||||
'/',
|
|
||||||
'Content-Length': '0',
|
|
||||||
});
|
|
||||||
response.end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let process;
|
|
||||||
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;
|
|
||||||
if ((match = /^\/\~(\w+)\/(\w+)$/.exec(blobId))) {
|
|
||||||
let user = match[1];
|
|
||||||
let appName = match[2];
|
|
||||||
let credentials = await httpd.auth_query(request.headers);
|
|
||||||
if (
|
|
||||||
credentials &&
|
|
||||||
credentials.session &&
|
|
||||||
(credentials.session.name == user ||
|
|
||||||
(credentials.permissions.administration && user == 'core'))
|
|
||||||
) {
|
|
||||||
let database = new Database(user);
|
|
||||||
|
|
||||||
let app_object = JSON.parse(utf8Decode(request.body));
|
|
||||||
let previous_id = await database.get('path:' + appName);
|
|
||||||
if (previous_id) {
|
|
||||||
try {
|
|
||||||
let previous_object = JSON.parse(
|
|
||||||
utf8Decode(await ssb.blobGet(previous_id))
|
|
||||||
);
|
|
||||||
delete previous_object.previous;
|
|
||||||
delete app_object.previous;
|
|
||||||
if (JSON.stringify(previous_object) == JSON.stringify(app_object)) {
|
|
||||||
response.writeHead(200, {
|
|
||||||
'Content-Type': 'text/plain; charset=utf-8',
|
|
||||||
});
|
|
||||||
response.end('/' + previous_id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
app_object.previous = previous_id;
|
|
||||||
let newBlobId = await ssb.blobStore(JSON.stringify(app_object));
|
|
||||||
|
|
||||||
let apps = new Set();
|
|
||||||
let apps_original = await database.get('apps');
|
|
||||||
try {
|
|
||||||
apps = new Set(JSON.parse(apps_original));
|
|
||||||
} catch {}
|
|
||||||
if (!apps.has(appName)) {
|
|
||||||
apps.add(appName);
|
|
||||||
}
|
|
||||||
apps = JSON.stringify([...apps].sort());
|
|
||||||
if (apps != apps_original) {
|
|
||||||
await database.set('apps', apps);
|
|
||||||
}
|
|
||||||
await database.set('path:' + appName, newBlobId);
|
|
||||||
response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
|
|
||||||
response.end('/' + newBlobId);
|
|
||||||
} else {
|
|
||||||
response.writeHead(401, {'Content-Type': 'text/plain; charset=utf-8'});
|
|
||||||
response.end('401 Unauthorized');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (blobId === '') {
|
|
||||||
let newBlobId = await ssb.blobStore(request.body);
|
|
||||||
response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
|
|
||||||
response.end('/' + newBlobId);
|
|
||||||
} else {
|
|
||||||
response.writeHead(400, {'Content-Type': 'text/plain; charset=utf-8'});
|
|
||||||
response.end('Invalid name.');
|
|
||||||
}
|
|
||||||
} else if (uri == '/delete') {
|
|
||||||
let match;
|
|
||||||
if ((match = /^\/\~(\w+)\/(\w+)$/.exec(blobId))) {
|
|
||||||
let user = match[1];
|
|
||||||
let appName = match[2];
|
|
||||||
let credentials = await httpd.auth_query(request.headers);
|
|
||||||
if (
|
|
||||||
credentials &&
|
|
||||||
credentials.session &&
|
|
||||||
(credentials.session.name == user ||
|
|
||||||
(credentials.permissions.administration && user == 'core'))
|
|
||||||
) {
|
|
||||||
let database = new Database(user);
|
|
||||||
let apps = new Set();
|
|
||||||
try {
|
|
||||||
apps = new Set(JSON.parse(await database.get('apps')));
|
|
||||||
} catch {}
|
|
||||||
if (apps.delete(appName)) {
|
|
||||||
await database.set('apps', JSON.stringify([...apps].sort()));
|
|
||||||
}
|
|
||||||
database.remove('path:' + appName);
|
|
||||||
} else {
|
|
||||||
response.writeHead(401, {'Content-Type': 'text/plain; charset=utf-8'});
|
|
||||||
response.end('401 Unauthorized');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
|
|
||||||
response.end('OK');
|
|
||||||
} else {
|
|
||||||
let data;
|
|
||||||
let match;
|
|
||||||
let id;
|
|
||||||
let app_id = blobId;
|
|
||||||
let packageOwner;
|
|
||||||
let packageName;
|
|
||||||
if ((match = /^\/\~(\w+)\/(\w+)$/.exec(blobId))) {
|
|
||||||
packageOwner = match[1];
|
|
||||||
packageName = match[2];
|
|
||||||
let db = new Database(match[1]);
|
|
||||||
app_id = await db.get('path:' + match[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let app_object = JSON.parse(utf8Decode(await ssb.blobGet(app_id)));
|
|
||||||
id = app_object?.files[uri.substring(1)];
|
|
||||||
if (!id && app_object?.files['handler.js']) {
|
|
||||||
let answer;
|
|
||||||
try {
|
|
||||||
answer = await useAppHandler(
|
|
||||||
response,
|
|
||||||
app_id,
|
|
||||||
uri.substring(1),
|
|
||||||
request.query ? form.decodeForm(request.query) : undefined,
|
|
||||||
request.headers,
|
|
||||||
packageOwner,
|
|
||||||
packageName
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
data = utf8Encode(
|
|
||||||
`Internal Server Error\n\n${error?.message}\n${error?.stack}`
|
|
||||||
);
|
|
||||||
response.writeHead(500, {
|
|
||||||
'Content-Type': 'text/plain; charset=utf-8',
|
|
||||||
'Content-Length': data.length,
|
|
||||||
});
|
|
||||||
response.end(data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (answer && typeof answer.data == 'string') {
|
|
||||||
answer.data = utf8Encode(answer.data);
|
|
||||||
}
|
|
||||||
sendData(
|
|
||||||
response,
|
|
||||||
answer?.data,
|
|
||||||
answer?.content_type,
|
|
||||||
Object.assign(answer?.headers ?? {}, {
|
|
||||||
'Access-Control-Allow-Origin': '*',
|
|
||||||
'Content-Security-Policy': k_content_security_policy,
|
|
||||||
}),
|
|
||||||
answer.status_code
|
|
||||||
);
|
|
||||||
} else if (id) {
|
|
||||||
if (
|
|
||||||
request.headers['if-none-match'] &&
|
|
||||||
request.headers['if-none-match'] == '"' + id + '"'
|
|
||||||
) {
|
|
||||||
let headers = {
|
|
||||||
'Access-Control-Allow-Origin': '*',
|
|
||||||
'Content-Security-Policy': k_content_security_policy,
|
|
||||||
'Content-Length': '0',
|
|
||||||
};
|
|
||||||
response.writeHead(304, headers);
|
|
||||||
response.end();
|
|
||||||
} else {
|
|
||||||
let headers = {
|
|
||||||
ETag: '"' + id + '"',
|
|
||||||
'Access-Control-Allow-Origin': '*',
|
|
||||||
'Content-Security-Policy': k_content_security_policy,
|
|
||||||
};
|
|
||||||
data = await ssb.blobGet(id);
|
|
||||||
let type =
|
|
||||||
httpd.mime_type_from_extension(uri) ||
|
|
||||||
httpd.mime_type_from_magic_bytes(data);
|
|
||||||
sendData(response, data, type, headers);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sendData(response, data, undefined, {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ssb.addEventListener('message', function () {
|
ssb.addEventListener('message', function () {
|
||||||
broadcastEvent('onMessage', [...arguments]);
|
broadcastEvent('onMessage', [...arguments]);
|
||||||
});
|
});
|
||||||
@ -1219,12 +754,12 @@ async function loadSettings() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
print('Settings not found in database:', error);
|
print('Settings not found in database:', error);
|
||||||
}
|
}
|
||||||
for (let [key, value] of Object.entries(k_global_settings)) {
|
for (let [key, value] of Object.entries(defaultGlobalSettings())) {
|
||||||
if (data[key] === undefined) {
|
if (data[key] === undefined) {
|
||||||
data[key] = value.default_value;
|
data[key] = value.default_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gGlobalSettings = data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1232,7 +767,7 @@ async function loadSettings() {
|
|||||||
*/
|
*/
|
||||||
function sendStats() {
|
function sendStats() {
|
||||||
let apps = Object.values(gProcesses)
|
let apps = Object.values(gProcesses)
|
||||||
.filter((process) => process.app && process.stats)
|
.filter((process) => process.app)
|
||||||
.map((process) => process.app);
|
.map((process) => process.app);
|
||||||
if (apps.length) {
|
if (apps.length) {
|
||||||
let stats = getStats();
|
let stats = getStats();
|
||||||
@ -1245,47 +780,82 @@ function sendStats() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
let g_handler_index = 0;
|
||||||
* TODOC
|
|
||||||
* @param {*} process
|
exports.callAppHandler = async function callAppHandler(
|
||||||
* @param {*} enabled
|
response,
|
||||||
*/
|
app_blob_id,
|
||||||
function enableStats(process, enabled) {
|
path,
|
||||||
process.stats = enabled;
|
query,
|
||||||
if (!gStatsTimer) {
|
headers,
|
||||||
gStatsTimer = true;
|
package_owner,
|
||||||
sendStats();
|
package_name
|
||||||
|
) {
|
||||||
|
let answer;
|
||||||
|
try {
|
||||||
|
let do_resolve;
|
||||||
|
let promise = new Promise(async function (resolve, reject) {
|
||||||
|
do_resolve = resolve;
|
||||||
|
});
|
||||||
|
let process;
|
||||||
|
try {
|
||||||
|
process = await getProcessBlob(
|
||||||
|
app_blob_id,
|
||||||
|
'handler_' + g_handler_index++,
|
||||||
|
{
|
||||||
|
script: 'handler.js',
|
||||||
|
imports: {
|
||||||
|
request: {
|
||||||
|
path: path,
|
||||||
|
query: query,
|
||||||
|
},
|
||||||
|
respond: do_resolve,
|
||||||
|
},
|
||||||
|
credentials: await httpd.auth_query(headers),
|
||||||
|
packageOwner: package_owner,
|
||||||
|
packageName: package_name,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await process.ready;
|
||||||
|
answer = await promise;
|
||||||
|
} finally {
|
||||||
|
if (process?.task) {
|
||||||
|
await process.task.kill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
let data = utf8Encode(
|
||||||
|
`Internal Server Error\n\n${error?.message}\n${error?.stack}`
|
||||||
|
);
|
||||||
|
response.writeHead(500, {
|
||||||
|
'Content-Type': 'text/plain; charset=utf-8',
|
||||||
|
'Content-Length': data.length,
|
||||||
|
});
|
||||||
|
response.end(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof answer?.data == 'string') {
|
||||||
|
answer.data = utf8Encode(answer.data);
|
||||||
|
}
|
||||||
|
response.writeHead(answer?.status_code, {
|
||||||
|
'Content-Type': answer?.content_type,
|
||||||
|
'Content-Length': answer?.data?.length,
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Content-Security-Policy':
|
||||||
|
'sandbox allow-downloads allow-top-navigation-by-user-activation',
|
||||||
|
});
|
||||||
|
response.end(answer?.data);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* TODOC
|
||||||
*/
|
*/
|
||||||
loadSettings()
|
loadSettings()
|
||||||
.then(function () {
|
.then(function (settings) {
|
||||||
if (tildefriends.https_port && gGlobalSettings.http_redirect) {
|
if (tildefriends.https_port && settings.http_redirect) {
|
||||||
httpd.set_http_redirect(gGlobalSettings.http_redirect);
|
httpd.set_http_redirect(settings.http_redirect);
|
||||||
}
|
}
|
||||||
httpd.all('/app/socket', app.socket);
|
httpd.all('/app/socket', app.socket);
|
||||||
httpd.all('', function default_http_handler(request, response) {
|
|
||||||
let match;
|
|
||||||
if ((match = /^(\/~[^\/]+\/[^\/]+)(\/?.*)$/.exec(request.uri))) {
|
|
||||||
return blobHandler(request, response, match[1], match[2]);
|
|
||||||
} else if (
|
|
||||||
(match = /^\/([&\%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(request.uri))
|
|
||||||
) {
|
|
||||||
return blobHandler(request, response, match[1], match[2]);
|
|
||||||
} else if ((match = /^(.*)(\/(?:save|delete)?)$/.exec(request.uri))) {
|
|
||||||
return blobHandler(request, response, match[1], match[2]);
|
|
||||||
} else {
|
|
||||||
let data = 'File not found.';
|
|
||||||
response.writeHead(404, {
|
|
||||||
'Content-Type': 'text/plain; charset=utf-8',
|
|
||||||
'Content-Length': data.length.toString(),
|
|
||||||
});
|
|
||||||
return response.end(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let port = httpd.start(tildefriends.http_port);
|
let port = httpd.start(tildefriends.http_port);
|
||||||
if (tildefriends.args.out_http_port_file) {
|
if (tildefriends.args.out_http_port_file) {
|
||||||
print('Writing the port file.');
|
print('Writing the port file.');
|
||||||
@ -1332,49 +902,4 @@ 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,
|
|
||||||
setGlobalSettings,
|
|
||||||
enableStats,
|
|
||||||
invoke,
|
|
||||||
getSessionProcessBlob,
|
|
||||||
};
|
|
||||||
|
@ -25,6 +25,17 @@
|
|||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
<noscript>
|
||||||
|
<div class="w3-container">
|
||||||
|
<div class="w3-panel w3-red w3-padding w3-card-4">
|
||||||
|
<h1>TildeFriends requires JavaScript.</h1>
|
||||||
|
<p>
|
||||||
|
It looks like JavaScript is disabled or unsupported. This isn't
|
||||||
|
going to work.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</noscript>
|
||||||
<tf-navigation></tf-navigation>
|
<tf-navigation></tf-navigation>
|
||||||
<div id="content" class="hbox" style="flex: 1 0; overflow: auto">
|
<div id="content" class="hbox" style="flex: 1 0; overflow: auto">
|
||||||
<div
|
<div
|
||||||
|
@ -1 +1,88 @@
|
|||||||
<svg width="65" height="65" viewBox="0 0 61 65" fill="none" xmlns="http://www.w3.org/2000/svg"><path style="fill:#0af;stroke-width:.712717;fill-opacity:1" d="M6 0h49a8 8 45 0 1 8 8v49a8 8 135 0 1-8 8H6a8 8 45 0 1-8-8V8a8 8 135 0 1 8-8Z"/><text xml:space="preserve" style="font-style:normal;font-weight:400;font-size:40px;line-height:1.25;font-family:sans-serif;fill:#000;fill-opacity:1;stroke:none" x="-.023" y="47.568"><tspan x="-.023" y="47.568" style="font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;font-size:40px;font-family:Arial;-inkscape-font-specification:'Arial, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal">~</tspan></text><g transform="translate(16.213 5.975) scale(.72923)"><circle cx="36" cy="36" r="23" fill="#fcea2b"/><path fill="#3f3f3f" d="M45.331 38.564c3.963 0 7.178-2.862 7.178-6.389 0-1.765.448-3.53-.852-4.685-1.299-1.156-4.345-1.704-6.326-1.704-2.357 0-5.143.143-6.451 1.704-.894 1.065-.727 3.253-.727 4.685 0 3.527 3.213 6.389 7.178 6.389zM25.738 38.564c3.963 0 7.179-2.862 7.179-6.389 0-1.765.447-3.53-.852-4.685-1.3-1.156-4.345-1.704-6.327-1.704-2.356 0-5.142.143-6.451 1.704-.893 1.065-.727 3.253-.727 4.685 0 3.527 3.213 6.389 7.178 6.389z"/></g><g stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2" transform="translate(16.213 5.975) scale(.72923)"><circle cx="35.887" cy="36.056" r="23"/><path d="M45.702 44.862c-6.574 3.525-14.045 3.658-19.63 0M18.883 30.464s-.953 8.55 6.86 7.918c2.62-.212 7.817-.65 7.867-8.342.005-.698-.007-1.6-.81-2.63-1.065-1.367-3.572-1.971-9.945-1.422 0 0-3.446-.1-3.972 4.476z"/><path d="m18.953 29.931-.433-3.372 3.833-.527M52.741 30.464s.953 8.55-6.86 7.918c-2.62-.212-7.817-.65-7.868-8.342-.004-.698.008-1.6.811-2.63 1.065-1.367 3.572-1.971 9.945-1.422 0 0 3.446-.1 3.972 4.476z"/><path d="M31.505 26.416s4.124 2.534 8.657 0M33.536 31.318s2.202-3.751 4.536 0M52.664 29.933l.433-3.371-3.833-.528"/><path d="M33.955 30.027s1.795-3.75 3.699 0"/></g></svg>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="65"
|
||||||
|
height="65"
|
||||||
|
viewBox="0 0 61 65"
|
||||||
|
fill="none"
|
||||||
|
version="1.1"
|
||||||
|
id="svg910"
|
||||||
|
sodipodi:docname="tildefriends.svg"
|
||||||
|
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs914" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview912"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="18.369231"
|
||||||
|
inkscape:cx="32.472781"
|
||||||
|
inkscape:cy="32.5"
|
||||||
|
inkscape:window-width="2256"
|
||||||
|
inkscape:window-height="1447"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg910" />
|
||||||
|
<path
|
||||||
|
style="fill:#0af;stroke-width:.712717;fill-opacity:1"
|
||||||
|
d="M6 0h49a8 8 45 0 1 8 8v49a8 8 135 0 1-8 8H6a8 8 45 0 1-8-8V8a8 8 135 0 1 8-8Z"
|
||||||
|
id="path886" />
|
||||||
|
<g
|
||||||
|
aria-label="~"
|
||||||
|
id="text890"
|
||||||
|
style="font-size:40px;line-height:1.25;fill:#000000">
|
||||||
|
<path
|
||||||
|
d="m 1.6762187,36.689095 v -4.003907 q 2.0703125,-2.34375 5.4296875,-2.34375 1.171875,0 2.4609375,0.351563 1.2890623,0.332031 3.6718753,1.347656 1.347656,0.566406 2.011718,0.742188 0.683594,0.175781 1.367188,0.175781 1.269531,0 2.617187,-0.761719 1.367188,-0.761719 2.421875,-1.914062 v 4.140625 q -1.25,1.171875 -2.539062,1.699218 -1.269531,0.527344 -2.871094,0.527344 -1.171875,0 -2.246094,-0.273437 -1.054687,-0.273438 -3.378906,-1.308594 -2.3046873,-1.035156 -3.847656,-1.035156 -1.25,0 -2.3632813,0.546875 -1.09375,0.527343 -2.734375,2.109375 z"
|
||||||
|
style="font-family:Arial;-inkscape-font-specification:'Arial, Normal'"
|
||||||
|
id="path1704" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="translate(16.213 5.975) scale(.72923)"
|
||||||
|
id="g896">
|
||||||
|
<circle
|
||||||
|
cx="36"
|
||||||
|
cy="36"
|
||||||
|
r="23"
|
||||||
|
fill="#fcea2b"
|
||||||
|
id="circle892" />
|
||||||
|
<path
|
||||||
|
fill="#3f3f3f"
|
||||||
|
d="M45.331 38.564c3.963 0 7.178-2.862 7.178-6.389 0-1.765.448-3.53-.852-4.685-1.299-1.156-4.345-1.704-6.326-1.704-2.357 0-5.143.143-6.451 1.704-.894 1.065-.727 3.253-.727 4.685 0 3.527 3.213 6.389 7.178 6.389zM25.738 38.564c3.963 0 7.179-2.862 7.179-6.389 0-1.765.447-3.53-.852-4.685-1.3-1.156-4.345-1.704-6.327-1.704-2.356 0-5.142.143-6.451 1.704-.893 1.065-.727 3.253-.727 4.685 0 3.527 3.213 6.389 7.178 6.389z"
|
||||||
|
id="path894" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
stroke="#000"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-miterlimit="10"
|
||||||
|
stroke-width="2"
|
||||||
|
transform="translate(16.213 5.975) scale(.72923)"
|
||||||
|
id="g908">
|
||||||
|
<circle
|
||||||
|
cx="35.887"
|
||||||
|
cy="36.056"
|
||||||
|
r="23"
|
||||||
|
id="circle898" />
|
||||||
|
<path
|
||||||
|
d="M45.702 44.862c-6.574 3.525-14.045 3.658-19.63 0M18.883 30.464s-.953 8.55 6.86 7.918c2.62-.212 7.817-.65 7.867-8.342.005-.698-.007-1.6-.81-2.63-1.065-1.367-3.572-1.971-9.945-1.422 0 0-3.446-.1-3.972 4.476z"
|
||||||
|
id="path900" />
|
||||||
|
<path
|
||||||
|
d="m18.953 29.931-.433-3.372 3.833-.527M52.741 30.464s.953 8.55-6.86 7.918c-2.62-.212-7.817-.65-7.868-8.342-.004-.698.008-1.6.811-2.63 1.065-1.367 3.572-1.971 9.945-1.422 0 0 3.446-.1 3.972 4.476z"
|
||||||
|
id="path902" />
|
||||||
|
<path
|
||||||
|
d="M31.505 26.416s4.124 2.534 8.657 0M33.536 31.318s2.202-3.751 4.536 0M52.664 29.933l.433-3.371-3.833-.528"
|
||||||
|
id="path904" />
|
||||||
|
<path
|
||||||
|
d="M33.955 30.027s1.795-3.75 3.699 0"
|
||||||
|
id="path906" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 3.6 KiB |
@ -21,14 +21,14 @@
|
|||||||
}:
|
}:
|
||||||
pkgs.stdenv.mkDerivation rec {
|
pkgs.stdenv.mkDerivation rec {
|
||||||
pname = "tildefriends";
|
pname = "tildefriends";
|
||||||
version = "0.0.20";
|
version = "0.0.24";
|
||||||
|
|
||||||
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-ttqL2wz06Jvn2f6kKIAGpF0nSSle+g4nSlj4jL0D+Fk=";
|
hash = "sha256-XlmRr08UmScY//qxUEXHzagXHCFqARRYr3q8RK/jKFY=";
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
1
deps/c-ares
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit a57ff692eeab8d21c853dc1ddaf0164f517074c3
|
177
deps/c-ares_config/ares_build.h
vendored
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
#ifndef __CARES_BUILD_H
|
||||||
|
#define __CARES_BUILD_H
|
||||||
|
/*
|
||||||
|
* Copyright (C) The c-ares project and its contributors
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CARES_STATICLIB
|
||||||
|
|
||||||
|
#ifdef CARES_HAVE_SYS_TYPES_H
|
||||||
|
# include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CARES_HAVE_SYS_SOCKET_H
|
||||||
|
# include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CARES_HAVE_SYS_SELECT_H
|
||||||
|
# include <sys/select.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#undef HAVE_REGISTERWAITFORSINGLEOBJECT
|
||||||
|
#define CARES_HAVE_WINSOCK2_H
|
||||||
|
#define CARES_HAVE_WINDOWS_H
|
||||||
|
#define CARES_HAVE_WS2TCPIP_H
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#define CARES_TYPEOF_ARES_SOCKLEN_T int
|
||||||
|
#define CARES_TYPEOF_ARES_SSIZE_T ssize_t
|
||||||
|
#else
|
||||||
|
#define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t
|
||||||
|
#define CARES_TYPEOF_ARES_SSIZE_T ssize_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__OpenBSD__) && !defined(__HAIKU__)
|
||||||
|
#define GETSERVBYNAME_R_ARGS 6
|
||||||
|
#define GETSERVBYPORT_R_ARGS 6
|
||||||
|
#define HAVE_GETSERVBYNAME_R 1
|
||||||
|
#define HAVE_GETSERVBYPORT_R 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__OpenBSD__) && !defined(__HAIKU__)
|
||||||
|
#define HAVE_PIPE2 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__OpenBSD__) || defined(__HAIKU__)
|
||||||
|
#define GETSERVBYNAME_R_ARGS 4
|
||||||
|
#define GETSERVBYPORT_R_ARGS 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__OpenBSD__) && !defined(__HAIKU__)
|
||||||
|
#define HAVE_MALLOC_H 1
|
||||||
|
#define HAVE_EPOLL 1
|
||||||
|
#define HAVE_SYS_EPOLL_H 1
|
||||||
|
#define HAVE_SYS_RANDOM_H 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__WIN32)
|
||||||
|
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||||
|
#undef ETC_INET
|
||||||
|
#define GETHOSTNAME_TYPE_ARG2 size_t
|
||||||
|
#define GETNAMEINFO_QUAL_ARG1
|
||||||
|
#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
|
||||||
|
#define GETNAMEINFO_TYPE_ARG2 socklen_t
|
||||||
|
#define GETNAMEINFO_TYPE_ARG46 socklen_t
|
||||||
|
#define GETNAMEINFO_TYPE_ARG7 int
|
||||||
|
#define HAVE_AF_INET6 1
|
||||||
|
#define HAVE_ARPA_INET_H 1
|
||||||
|
#define HAVE_ARPA_NAMESER_COMPAT_H 1
|
||||||
|
#define HAVE_ARPA_NAMESER_H 1
|
||||||
|
#define HAVE_ASSERT_H 1
|
||||||
|
#define HAVE_CLOCK_GETTIME_MONOTONIC 1
|
||||||
|
#define HAVE_CONNECT 1
|
||||||
|
#define HAVE_DLFCN_H 1
|
||||||
|
#define HAVE_ERRNO_H 1
|
||||||
|
#define HAVE_POLL_H 1
|
||||||
|
#define HAVE_POLL 1
|
||||||
|
#define HAVE_PIPE 1
|
||||||
|
#define HAVE_FCNTL 1
|
||||||
|
#define HAVE_FCNTL_H 1
|
||||||
|
#define HAVE_FCNTL_O_NONBLOCK 1
|
||||||
|
#define HAVE_FREEADDRINFO 1
|
||||||
|
#define HAVE_GETADDRINFO 1
|
||||||
|
#define HAVE_GETENV 1
|
||||||
|
#define HAVE_GETHOSTNAME 1
|
||||||
|
#define HAVE_GETNAMEINFO 1
|
||||||
|
#if !defined(__HAIKU__)
|
||||||
|
#define HAVE_GETRANDOM 1
|
||||||
|
#endif
|
||||||
|
#define HAVE_GETTIMEOFDAY 1
|
||||||
|
#define HAVE_IF_INDEXTONAME 1
|
||||||
|
#define HAVE_IF_NAMETOINDEX 1
|
||||||
|
#define HAVE_INET_NTOP 1
|
||||||
|
#define HAVE_INET_PTON 1
|
||||||
|
#define HAVE_INTTYPES_H 1
|
||||||
|
#define HAVE_IOCTL 1
|
||||||
|
#define HAVE_IOCTL_FIONBIO 1
|
||||||
|
#define HAVE_IOCTL_SIOCGIFADDR 1
|
||||||
|
#define HAVE_LIMITS_H 1
|
||||||
|
#define HAVE_LONGLONG 1
|
||||||
|
#define HAVE_MEMORY_H 1
|
||||||
|
#define HAVE_MSG_NOSIGNAL 1
|
||||||
|
#define HAVE_NETDB_H 1
|
||||||
|
#define HAVE_NETINET_IN_H 1
|
||||||
|
#define HAVE_NETINET_TCP_H 1
|
||||||
|
#define HAVE_NET_IF_H 1
|
||||||
|
#define HAVE_PF_INET6 1
|
||||||
|
#define HAVE_RECV 1
|
||||||
|
#define HAVE_RECVFROM 1
|
||||||
|
#define HAVE_SEND 1
|
||||||
|
#define HAVE_SETSOCKOPT 1
|
||||||
|
#define HAVE_SIGNAL_H 1
|
||||||
|
#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1
|
||||||
|
#define HAVE_SOCKET 1
|
||||||
|
#define HAVE_STDBOOL_H 1
|
||||||
|
#define HAVE_STDINT_H 1
|
||||||
|
#define HAVE_STDLIB_H 1
|
||||||
|
#define HAVE_STRCASECMP 1
|
||||||
|
#define HAVE_STRDUP 1
|
||||||
|
#define HAVE_STRINGS_H 1
|
||||||
|
#define HAVE_STRING_H 1
|
||||||
|
#define HAVE_STRNCASECMP 1
|
||||||
|
#define HAVE_STRUCT_ADDRINFO 1
|
||||||
|
#define HAVE_STRUCT_IN6_ADDR 1
|
||||||
|
#define HAVE_STRUCT_SOCKADDR_IN6 1
|
||||||
|
#define HAVE_STRUCT_SOCKADDR_STORAGE 1
|
||||||
|
#define HAVE_STRUCT_TIMEVAL 1
|
||||||
|
#define HAVE_SYS_IOCTL_H 1
|
||||||
|
#define HAVE_SYS_PARAM_H 1
|
||||||
|
#define HAVE_SYS_SELECT_H 1
|
||||||
|
#define HAVE_SYS_SOCKET_H 1
|
||||||
|
#define HAVE_SYS_STAT_H 1
|
||||||
|
#define HAVE_SYS_TIME_H 1
|
||||||
|
#define HAVE_SYS_TYPES_H 1
|
||||||
|
#define HAVE_SYS_UIO_H 1
|
||||||
|
#define HAVE_TIME_H 1
|
||||||
|
#define HAVE_IFADDRS_H 1
|
||||||
|
#define HAVE_UNISTD_H 1
|
||||||
|
#define HAVE_WRITEV 1
|
||||||
|
#if defined(__ANDROID__) || defined(__APPLE__) || defined(__OpenBSD__)
|
||||||
|
#define HAVE_ARC4RANDOM_BUF 1
|
||||||
|
#else
|
||||||
|
#undef HAVE_ARC4RANDOM_BUF
|
||||||
|
#endif
|
||||||
|
#define HAVE_GETIFADDRS 1
|
||||||
|
#define HAVE_STAT 1
|
||||||
|
#define CARES_RANDOM_FILE "/dev/urandom"
|
||||||
|
#define RECVFROM_QUAL_ARG5
|
||||||
|
#define RECVFROM_TYPE_ARG1 int
|
||||||
|
#define RECVFROM_TYPE_ARG2 void *
|
||||||
|
#define RECVFROM_TYPE_ARG2_IS_VOID 0
|
||||||
|
#define RECVFROM_TYPE_ARG3 size_t
|
||||||
|
#define RECVFROM_TYPE_ARG4 int
|
||||||
|
#define RECVFROM_TYPE_ARG5 struct sockaddr *
|
||||||
|
#define RECVFROM_TYPE_ARG5_IS_VOID 0
|
||||||
|
#define RECVFROM_TYPE_ARG6 socklen_t *
|
||||||
|
#define RECVFROM_TYPE_ARG6_IS_VOID 0
|
||||||
|
#define RECVFROM_TYPE_RETV ssize_t
|
||||||
|
#define RECV_TYPE_ARG1 int
|
||||||
|
#define RECV_TYPE_ARG2 void *
|
||||||
|
#define RECV_TYPE_ARG3 size_t
|
||||||
|
#define RECV_TYPE_ARG4 int
|
||||||
|
#define RECV_TYPE_RETV ssize_t
|
||||||
|
#define SEND_TYPE_ARG1 int
|
||||||
|
#define SEND_TYPE_ARG2 const void *
|
||||||
|
#define SEND_TYPE_ARG3 size_t
|
||||||
|
#define SEND_TYPE_ARG4 int
|
||||||
|
#define SEND_TYPE_RETV ssize_t
|
||||||
|
#undef USE_BLOCKING_SOCKETS
|
||||||
|
#undef WIN32_LEAN_AND_MEAN
|
||||||
|
#define HAVE_PTHREAD_H 1
|
||||||
|
#define CARES_THREADS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __CARES_BUILD_H */
|
2
deps/codemirror/cm6.js
vendored
417
deps/codemirror_src/package-lock.json
generated
vendored
@ -19,9 +19,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/autocomplete": {
|
"node_modules/@codemirror/autocomplete": {
|
||||||
"version": "6.16.2",
|
"version": "6.18.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.16.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.2.tgz",
|
||||||
"integrity": "sha512-MjfDrHy0gHKlPWsvSsikhO1+BOh+eBHNgfH1OXs1+DAf30IonQldgMM3kxLDTG9ktE7kDLaA1j/l7KMPA4KNfw==",
|
"integrity": "sha512-wJGylKtMFR/Ds6Gh01+OovXE/pncPiKZNNBKuC39pKnH+XK5d9+WsNqcrdxPjFPFTigRBqse0rfxw9UxrfyhPg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
@ -36,9 +37,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/commands": {
|
"node_modules/@codemirror/commands": {
|
||||||
"version": "6.6.0",
|
"version": "6.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.7.1.tgz",
|
||||||
"integrity": "sha512-qnY+b7j1UNcTS31Eenuc/5YJB6gQOzkUoNmJQc0rznwqSRpeaWWpjkWy2C/MPTcePpsKJEM26hXrOXl1+nceXg==",
|
"integrity": "sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.4.0",
|
"@codemirror/state": "^6.4.0",
|
||||||
@ -47,21 +49,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lang-css": {
|
"node_modules/@codemirror/lang-css": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.0.tgz",
|
||||||
"integrity": "sha512-/UNWDNV5Viwi/1lpr/dIXJNWiwDxpw13I4pTUAsNxZdg6E0mI2kTQb0P2iHczg1Tu+H4EBgJR+hYhKiHKko7qg==",
|
"integrity": "sha512-CyR4rUNG9OYcXDZwMPvJdtb6PHbBDKUc/6Na2BIwZ6dKab1JQqKa4di+RNRY9Myn7JB81vayKwJeQ7jEdmNVDA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@lezer/common": "^1.0.2",
|
"@lezer/common": "^1.0.2",
|
||||||
"@lezer/css": "^1.0.0"
|
"@lezer/css": "^1.1.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lang-html": {
|
"node_modules/@codemirror/lang-html": {
|
||||||
"version": "6.4.9",
|
"version": "6.4.9",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
|
||||||
"integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
|
"integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/lang-css": "^6.0.0",
|
"@codemirror/lang-css": "^6.0.0",
|
||||||
@ -78,6 +82,7 @@
|
|||||||
"version": "6.2.2",
|
"version": "6.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.2.tgz",
|
||||||
"integrity": "sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==",
|
"integrity": "sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/language": "^6.6.0",
|
"@codemirror/language": "^6.6.0",
|
||||||
@ -92,15 +97,17 @@
|
|||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz",
|
||||||
"integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==",
|
"integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@lezer/json": "^1.0.0"
|
"@lezer/json": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/language": {
|
"node_modules/@codemirror/language": {
|
||||||
"version": "6.10.2",
|
"version": "6.10.3",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.3.tgz",
|
||||||
"integrity": "sha512-kgbTYTo0Au6dCSc/TFy7fK3fpJmgHDv1sG1KNQKJXVi+xBTEeBPY/M30YXiU6mMXeH+YIDLsbrT4ZwNRdtF+SA==",
|
"integrity": "sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.23.0",
|
"@codemirror/view": "^6.23.0",
|
||||||
@ -111,9 +118,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lint": {
|
"node_modules/@codemirror/lint": {
|
||||||
"version": "6.8.0",
|
"version": "6.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.2.tgz",
|
||||||
"integrity": "sha512-lsFofvaw0lnPRJlQylNsC4IRt/1lI4OD/yYslrSGVndOJfStc58v+8p9dgGiD90ktOfL7OhBWns1ZETYgz0EJA==",
|
"integrity": "sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.0.0",
|
"@codemirror/view": "^6.0.0",
|
||||||
@ -121,9 +129,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/search": {
|
"node_modules/@codemirror/search": {
|
||||||
"version": "6.5.6",
|
"version": "6.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.7.tgz",
|
||||||
"integrity": "sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==",
|
"integrity": "sha512-6+iLsXvITWKHYlkgHPCs/qiX4dNzn8N78YfhOFvPtPYCkuXqZq10rAfsUMhOq7O/1VjJqdXRflyExlfVcu/9VQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.0.0",
|
"@codemirror/view": "^6.0.0",
|
||||||
@ -133,12 +142,14 @@
|
|||||||
"node_modules/@codemirror/state": {
|
"node_modules/@codemirror/state": {
|
||||||
"version": "6.4.1",
|
"version": "6.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz",
|
||||||
"integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A=="
|
"integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/theme-one-dark": {
|
"node_modules/@codemirror/theme-one-dark": {
|
||||||
"version": "6.1.2",
|
"version": "6.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz",
|
||||||
"integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==",
|
"integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
@ -147,9 +158,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/view": {
|
"node_modules/@codemirror/view": {
|
||||||
"version": "6.28.1",
|
"version": "6.34.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.2.tgz",
|
||||||
"integrity": "sha512-BUWr+zCJpMkA/u69HlJmR+YkV4yPpM81HeMkOMZuwFa8iM5uJdEPKAs1icIRZKkKmy0Ub1x9/G3PQLTXdpBxrQ==",
|
"integrity": "sha512-d6n0WFvL970A9Z+l9N2dO+Hk9ev4hDYQzIx+B9tCyBP0W5wPEszi1rhuyFesNSkLZzXbQE5FPH7F/z/TMJfoPA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.4.0",
|
"@codemirror/state": "^6.4.0",
|
||||||
"style-mod": "^4.1.0",
|
"style-mod": "^4.1.0",
|
||||||
@ -161,6 +173,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||||
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/set-array": "^1.2.1",
|
"@jridgewell/set-array": "^1.2.1",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||||
@ -175,6 +188,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
@ -184,6 +198,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
||||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
@ -193,36 +208,41 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
|
||||||
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
|
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.3.5",
|
"@jridgewell/gen-mapping": "^0.3.5",
|
||||||
"@jridgewell/trace-mapping": "^0.3.25"
|
"@jridgewell/trace-mapping": "^0.3.25"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.15",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
"version": "0.3.25",
|
"version": "0.3.25",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "^3.1.0",
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/common": {
|
"node_modules/@lezer/common": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
|
||||||
"integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ=="
|
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/css": {
|
"node_modules/@lezer/css": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.9.tgz",
|
||||||
"integrity": "sha512-7JhxupKuMBaWQKjQoLtzhGj83DdnZY9MckEOG5+/iLKNK2ZJqKc6hf6uc0HjwCX7Qlok44jBNqZhHKDhEhZYLA==",
|
"integrity": "sha512-TYwgljcDv+YrV0MZFFvYFQHCfGgbPMR6nuqLabBdmZoFH3EP1gvw8t0vae326Ne3PszQkbXfVBjCnf3ZVCr0bA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
@ -230,9 +250,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/highlight": {
|
"node_modules/@lezer/highlight": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
|
||||||
"integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==",
|
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.0.0"
|
"@lezer/common": "^1.0.0"
|
||||||
}
|
}
|
||||||
@ -241,6 +262,7 @@
|
|||||||
"version": "1.3.10",
|
"version": "1.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz",
|
||||||
"integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==",
|
"integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
@ -248,9 +270,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/javascript": {
|
"node_modules/@lezer/javascript": {
|
||||||
"version": "1.4.17",
|
"version": "1.4.19",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.17.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.19.tgz",
|
||||||
"integrity": "sha512-bYW4ctpyGK+JMumDApeUzuIezX01H76R1foD6LcRX224FWfyYit/HYxiPGDjXXe/wQWASjCvVGoukTH68+0HIA==",
|
"integrity": "sha512-j44kbR1QL26l6dMunZ1uhKBFteVGLVCBGNUD2sUaMnic+rbTviVuoK0CD1l9FTW31EueWvFFswCKMH7Z+M3JRA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.1.3",
|
"@lezer/highlight": "^1.1.3",
|
||||||
@ -261,6 +284,7 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.2.tgz",
|
||||||
"integrity": "sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==",
|
"integrity": "sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
@ -268,22 +292,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/lr": {
|
"node_modules/@lezer/lr": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
|
||||||
"integrity": "sha512-CHsKq8DMKBf9b3yXPDIU4DbH+ZJd/sJdYOW2llbW/HudP5u0VS6Bfq1hLYfgU7uAYGFIyGGQIsSOXGPEErZiJw==",
|
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.0.0"
|
"@lezer/common": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/plugin-node-resolve": {
|
"node_modules/@rollup/plugin-node-resolve": {
|
||||||
"version": "15.2.3",
|
"version": "15.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz",
|
||||||
"integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==",
|
"integrity": "sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==",
|
||||||
|
"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"
|
||||||
},
|
},
|
||||||
@ -304,6 +329,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
||||||
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
|
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"serialize-javascript": "^6.0.1",
|
"serialize-javascript": "^6.0.1",
|
||||||
"smob": "^1.0.0",
|
"smob": "^1.0.0",
|
||||||
@ -322,13 +348,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/pluginutils": {
|
"node_modules/@rollup/pluginutils": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz",
|
||||||
"integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==",
|
"integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "^1.0.0",
|
"@types/estree": "^1.0.0",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"picomatch": "^2.3.1"
|
"picomatch": "^4.0.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
@ -343,212 +370,257 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.4.tgz",
|
||||||
"integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==",
|
"integrity": "sha512-jfUJrFct/hTA0XDM5p/htWKoNNTbDLY0KRwEt6pyOA6k2fmk0WVwl65PdUdJZgzGEHWx+49LilkcSaumQRyNQw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm64": {
|
"node_modules/@rollup/rollup-android-arm64": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.4.tgz",
|
||||||
"integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==",
|
"integrity": "sha512-j4nrEO6nHU1nZUuCfRKoCcvh7PIywQPUCBa2UsootTHvTHIoIu2BzueInGJhhvQO/2FTRdNYpf63xsgEqH9IhA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.4.tgz",
|
||||||
"integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==",
|
"integrity": "sha512-GmU/QgGtBTeraKyldC7cDVVvAJEOr3dFLKneez/n7BvX57UdhOqDsVwzU7UOnYA7AAOt+Xb26lk79PldDHgMIQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-x64": {
|
"node_modules/@rollup/rollup-darwin-x64": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.4.tgz",
|
||||||
"integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==",
|
"integrity": "sha512-N6oDBiZCBKlwYcsEPXGDE4g9RoxZLK6vT98M8111cW7VsVJFpNEqvJeIPfsCzbf0XEakPslh72X0gnlMi4Ddgg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||||
|
"version": "4.24.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.24.4.tgz",
|
||||||
|
"integrity": "sha512-py5oNShCCjCyjWXCZNrRGRpjWsF0ic8f4ieBNra5buQz0O/U6mMXCpC1LvrHuhJsNPgRt36tSYMidGzZiJF6mw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||||
|
"version": "4.24.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.24.4.tgz",
|
||||||
|
"integrity": "sha512-L7VVVW9FCnTTp4i7KrmHeDsDvjB4++KOBENYtNYAiYl96jeBThFfhP6HVxL74v4SiZEVDH/1ILscR5U9S4ms4g==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.4.tgz",
|
||||||
"integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==",
|
"integrity": "sha512-10ICosOwYChROdQoQo589N5idQIisxjaFE/PAnX2i0Zr84mY0k9zul1ArH0rnJ/fpgiqfu13TFZR5A5YJLOYZA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.4.tgz",
|
||||||
"integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==",
|
"integrity": "sha512-ySAfWs69LYC7QhRDZNKqNhz2UKN8LDfbKSMAEtoEI0jitwfAG2iZwVqGACJT+kfYvvz3/JgsLlcBP+WWoKCLcw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.4.tgz",
|
||||||
"integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==",
|
"integrity": "sha512-uHYJ0HNOI6pGEeZ/5mgm5arNVTI0nLlmrbdph+pGXpC9tFHFDQmDMOEqkmUObRfosJqpU8RliYoGz06qSdtcjg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.4.tgz",
|
||||||
"integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==",
|
"integrity": "sha512-38yiWLemQf7aLHDgTg85fh3hW9stJ0Muk7+s6tIkSUOMmi4Xbv5pH/5Bofnsb6spIwD5FJiR+jg71f0CH5OzoA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.4.tgz",
|
||||||
"integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==",
|
"integrity": "sha512-q73XUPnkwt9ZNF2xRS4fvneSuaHw2BXuV5rI4cw0fWYVIWIBeDZX7c7FWhFQPNTnE24172K30I+dViWRVD9TwA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.4.tgz",
|
||||||
"integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==",
|
"integrity": "sha512-Aie/TbmQi6UXokJqDZdmTJuZBCU3QBDA8oTKRGtd4ABi/nHgXICulfg1KI6n9/koDsiDbvHAiQO3YAUNa/7BCw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.4.tgz",
|
||||||
"integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==",
|
"integrity": "sha512-P8MPErVO/y8ohWSP9JY7lLQ8+YMHfTI4bAdtCi3pC2hTeqFJco2jYspzOzTUB8hwUWIIu1xwOrJE11nP+0JFAQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.4.tgz",
|
||||||
"integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==",
|
"integrity": "sha512-K03TljaaoPK5FOyNMZAAEmhlyO49LaE4qCsr0lYHUKyb6QacTNF9pnfPpXnFlFD3TXuFbFbz7tJ51FujUXkXYA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.4.tgz",
|
||||||
"integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==",
|
"integrity": "sha512-VJYl4xSl/wqG2D5xTYncVWW+26ICV4wubwN9Gs5NrqhJtayikwCXzPL8GDsLnaLU3WwhQ8W02IinYSFJfyo34Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.4.tgz",
|
||||||
"integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==",
|
"integrity": "sha512-ku2GvtPwQfCqoPFIJCqZ8o7bJcj+Y54cZSr43hHca6jLwAiCbZdBUOrqE6y29QFajNAzzpIOwsckaTFmN6/8TA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.4.tgz",
|
||||||
"integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==",
|
"integrity": "sha512-V3nCe+eTt/W6UYNr/wGvO1fLpHUrnlirlypZfKCT1fG6hWfqhPgQV/K/mRBXBpxc0eKLIF18pIOFVPh0mqHjlg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.4.tgz",
|
||||||
"integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==",
|
"integrity": "sha512-LTw1Dfd0mBIEqUVCxbvTE/LLo+9ZxVC9k99v1v4ahg9Aak6FpqOfNu5kRkeTAn0wphoC4JU7No1/rL+bBCEwhg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/resolve": {
|
"node_modules/@types/resolve": {
|
||||||
"version": "1.20.2",
|
"version": "1.20.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
||||||
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="
|
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.12.0",
|
"version": "8.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
||||||
"integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==",
|
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@ -560,23 +632,14 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
},
|
"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==",
|
|
||||||
"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",
|
||||||
"integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
|
"integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/commands": "^6.0.0",
|
"@codemirror/commands": "^6.0.0",
|
||||||
@ -591,17 +654,20 @@
|
|||||||
"version": "2.20.3",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/crelt": {
|
"node_modules/crelt": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||||
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
|
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/deepmerge": {
|
"node_modules/deepmerge": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -609,13 +675,15 @@
|
|||||||
"node_modules/estree-walker": {
|
"node_modules/estree-walker": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
@ -628,6 +696,7 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
@ -636,6 +705,7 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
},
|
},
|
||||||
@ -643,26 +713,16 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-builtin-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "3.2.1",
|
"version": "2.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
|
||||||
"integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
|
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"builtin-modules": "^3.3.0"
|
"hasown": "^2.0.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">= 0.4"
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/is-core-module": {
|
|
||||||
"version": "2.13.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
|
|
||||||
"integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
|
|
||||||
"dependencies": {
|
|
||||||
"hasown": "^2.0.0"
|
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
@ -671,19 +731,22 @@
|
|||||||
"node_modules/is-module": {
|
"node_modules/is-module": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
||||||
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="
|
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/path-parse": {
|
"node_modules/path-parse": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "2.3.1",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
||||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.6"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
@ -694,6 +757,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"safe-buffer": "^5.1.0"
|
"safe-buffer": "^5.1.0"
|
||||||
}
|
}
|
||||||
@ -702,6 +766,7 @@
|
|||||||
"version": "1.22.8",
|
"version": "1.22.8",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||||
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-core-module": "^2.13.0",
|
"is-core-module": "^2.13.0",
|
||||||
"path-parse": "^1.0.7",
|
"path-parse": "^1.0.7",
|
||||||
@ -715,11 +780,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.18.0",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.4.tgz",
|
||||||
"integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==",
|
"integrity": "sha512-vGorVWIsWfX3xbcyAS+I047kFKapHYivmkaT63Smj77XwvLSJos6M1xGqZnBPFQFBRZDOcG1QnYEIxAvTr/HjA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.5"
|
"@types/estree": "1.0.6"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
@ -729,22 +795,24 @@
|
|||||||
"npm": ">=8.0.0"
|
"npm": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-android-arm-eabi": "4.18.0",
|
"@rollup/rollup-android-arm-eabi": "4.24.4",
|
||||||
"@rollup/rollup-android-arm64": "4.18.0",
|
"@rollup/rollup-android-arm64": "4.24.4",
|
||||||
"@rollup/rollup-darwin-arm64": "4.18.0",
|
"@rollup/rollup-darwin-arm64": "4.24.4",
|
||||||
"@rollup/rollup-darwin-x64": "4.18.0",
|
"@rollup/rollup-darwin-x64": "4.24.4",
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": "4.18.0",
|
"@rollup/rollup-freebsd-arm64": "4.24.4",
|
||||||
"@rollup/rollup-linux-arm-musleabihf": "4.18.0",
|
"@rollup/rollup-freebsd-x64": "4.24.4",
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.18.0",
|
"@rollup/rollup-linux-arm-gnueabihf": "4.24.4",
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.18.0",
|
"@rollup/rollup-linux-arm-musleabihf": "4.24.4",
|
||||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.18.0",
|
"@rollup/rollup-linux-arm64-gnu": "4.24.4",
|
||||||
"@rollup/rollup-linux-riscv64-gnu": "4.18.0",
|
"@rollup/rollup-linux-arm64-musl": "4.24.4",
|
||||||
"@rollup/rollup-linux-s390x-gnu": "4.18.0",
|
"@rollup/rollup-linux-powerpc64le-gnu": "4.24.4",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.18.0",
|
"@rollup/rollup-linux-riscv64-gnu": "4.24.4",
|
||||||
"@rollup/rollup-linux-x64-musl": "4.18.0",
|
"@rollup/rollup-linux-s390x-gnu": "4.24.4",
|
||||||
"@rollup/rollup-win32-arm64-msvc": "4.18.0",
|
"@rollup/rollup-linux-x64-gnu": "4.24.4",
|
||||||
"@rollup/rollup-win32-ia32-msvc": "4.18.0",
|
"@rollup/rollup-linux-x64-musl": "4.24.4",
|
||||||
"@rollup/rollup-win32-x64-msvc": "4.18.0",
|
"@rollup/rollup-win32-arm64-msvc": "4.24.4",
|
||||||
|
"@rollup/rollup-win32-ia32-msvc": "4.24.4",
|
||||||
|
"@rollup/rollup-win32-x64-msvc": "4.24.4",
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -766,13 +834,15 @@
|
|||||||
"type": "consulting",
|
"type": "consulting",
|
||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/serialize-javascript": {
|
"node_modules/serialize-javascript": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
||||||
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
|
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"randombytes": "^2.1.0"
|
"randombytes": "^2.1.0"
|
||||||
}
|
}
|
||||||
@ -781,13 +851,15 @@
|
|||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
|
||||||
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
|
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -797,6 +869,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buffer-from": "^1.0.0",
|
"buffer-from": "^1.0.0",
|
||||||
"source-map": "^0.6.0"
|
"source-map": "^0.6.0"
|
||||||
@ -805,12 +878,14 @@
|
|||||||
"node_modules/style-mod": {
|
"node_modules/style-mod": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
||||||
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="
|
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/supports-preserve-symlinks-flag": {
|
"node_modules/supports-preserve-symlinks-flag": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
@ -819,10 +894,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.31.1",
|
"version": "5.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz",
|
||||||
"integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==",
|
"integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/source-map": "^0.3.3",
|
"@jridgewell/source-map": "^0.3.3",
|
||||||
"acorn": "^8.8.2",
|
"acorn": "^8.8.2",
|
||||||
@ -839,7 +915,8 @@
|
|||||||
"node_modules/w3c-keyname": {
|
"node_modules/w3c-keyname": {
|
||||||
"version": "2.2.8",
|
"version": "2.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||||
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
|
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
||||||
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
deps/libbacktrace
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 4ead348bb45f753121ca0bd44170ff8352d4c514
|
Subproject commit d48f84034ce3e53e501d10593710d025cb1121db
|
2
deps/libsodium
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 9511c982fb1d046470a8b42aa36556cdb7da15de
|
Subproject commit 0217d07326f0ffbe79d6ce09793843e135a67487
|
2
deps/libuv
vendored
@ -1 +1 @@
|
|||||||
Subproject commit e9f29cb984231524e3931aa0ae2c5dae1a32884e
|
Subproject commit e1095c7a4373ce00cd8874d8e820de5afb25776e
|
42
deps/lit/lit-all.min.js
vendored
2
deps/lit/lit-all.min.js.map
vendored
1
deps/openssl_src
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 98acb6b02839c609ef5b837794e08d906d965335
|
6024
deps/sqlite/shell.c
vendored
7685
deps/sqlite/sqlite3.c
vendored
193
deps/sqlite/sqlite3.h
vendored
@ -146,9 +146,9 @@ extern "C" {
|
|||||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||||
** [sqlite_version()] and [sqlite_source_id()].
|
** [sqlite_version()] and [sqlite_source_id()].
|
||||||
*/
|
*/
|
||||||
#define SQLITE_VERSION "3.46.0"
|
#define SQLITE_VERSION "3.47.0"
|
||||||
#define SQLITE_VERSION_NUMBER 3046000
|
#define SQLITE_VERSION_NUMBER 3047000
|
||||||
#define SQLITE_SOURCE_ID "2024-05-23 13:25:27 96c92aba00c8375bc32fafcdf12429c58bd8aabfcadab6683e35bbb9cdebf19e"
|
#define SQLITE_SOURCE_ID "2024-10-21 16:30:22 03a9703e27c44437c39363d0baf82db4ebc94538a0f28411c85dda156f82636e"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Run-Time Library Version Numbers
|
** CAPI3REF: Run-Time Library Version Numbers
|
||||||
@ -772,8 +772,8 @@ struct sqlite3_file {
|
|||||||
** to xUnlock() is a no-op.
|
** to xUnlock() is a no-op.
|
||||||
** The xCheckReservedLock() method checks whether any database connection,
|
** The xCheckReservedLock() method checks whether any database connection,
|
||||||
** either in this process or in some other process, is holding a RESERVED,
|
** either in this process or in some other process, is holding a RESERVED,
|
||||||
** PENDING, or EXCLUSIVE lock on the file. It returns true
|
** PENDING, or EXCLUSIVE lock on the file. It returns, via its output
|
||||||
** if such a lock exists and false otherwise.
|
** pointer parameter, true if such a lock exists and false otherwise.
|
||||||
**
|
**
|
||||||
** The xFileControl() method is a generic interface that allows custom
|
** The xFileControl() method is a generic interface that allows custom
|
||||||
** VFS implementations to directly control an open file using the
|
** VFS implementations to directly control an open file using the
|
||||||
@ -3570,8 +3570,8 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|||||||
**
|
**
|
||||||
** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt>
|
** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt>
|
||||||
** <dd>The database connection comes up in "extended result code mode".
|
** <dd>The database connection comes up in "extended result code mode".
|
||||||
** In other words, the database behaves has if
|
** In other words, the database behaves as if
|
||||||
** [sqlite3_extended_result_codes(db,1)] where called on the database
|
** [sqlite3_extended_result_codes(db,1)] were called on the database
|
||||||
** connection as soon as the connection is created. In addition to setting
|
** connection as soon as the connection is created. In addition to setting
|
||||||
** the extended result code mode, this flag also causes [sqlite3_open_v2()]
|
** the extended result code mode, this flag also causes [sqlite3_open_v2()]
|
||||||
** to return an extended result code.</dd>
|
** to return an extended result code.</dd>
|
||||||
@ -4222,13 +4222,17 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
|
|||||||
** and sqlite3_prepare16_v3() use UTF-16.
|
** and sqlite3_prepare16_v3() use UTF-16.
|
||||||
**
|
**
|
||||||
** ^If the nByte argument is negative, then zSql is read up to the
|
** ^If the nByte argument is negative, then zSql is read up to the
|
||||||
** first zero terminator. ^If nByte is positive, then it is the
|
** first zero terminator. ^If nByte is positive, then it is the maximum
|
||||||
** number of bytes read from zSql. ^If nByte is zero, then no prepared
|
** number of bytes read from zSql. When nByte is positive, zSql is read
|
||||||
|
** up to the first zero terminator or until the nByte bytes have been read,
|
||||||
|
** whichever comes first. ^If nByte is zero, then no prepared
|
||||||
** statement is generated.
|
** statement is generated.
|
||||||
** If the caller knows that the supplied string is nul-terminated, then
|
** If the caller knows that the supplied string is nul-terminated, then
|
||||||
** there is a small performance advantage to passing an nByte parameter that
|
** there is a small performance advantage to passing an nByte parameter that
|
||||||
** is the number of bytes in the input string <i>including</i>
|
** is the number of bytes in the input string <i>including</i>
|
||||||
** the nul-terminator.
|
** the nul-terminator.
|
||||||
|
** Note that nByte measure the length of the input in bytes, not
|
||||||
|
** characters, even for the UTF-16 interfaces.
|
||||||
**
|
**
|
||||||
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
|
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
|
||||||
** past the end of the first SQL statement in zSql. These routines only
|
** past the end of the first SQL statement in zSql. These routines only
|
||||||
@ -5599,7 +5603,7 @@ SQLITE_API int sqlite3_create_window_function(
|
|||||||
** This flag instructs SQLite to omit some corner-case optimizations that
|
** This flag instructs SQLite to omit some corner-case optimizations that
|
||||||
** might disrupt the operation of the [sqlite3_value_subtype()] function,
|
** might disrupt the operation of the [sqlite3_value_subtype()] function,
|
||||||
** causing it to return zero rather than the correct subtype().
|
** causing it to return zero rather than the correct subtype().
|
||||||
** SQL functions that invokes [sqlite3_value_subtype()] should have this
|
** All SQL functions that invoke [sqlite3_value_subtype()] should have this
|
||||||
** property. If the SQLITE_SUBTYPE property is omitted, then the return
|
** property. If the SQLITE_SUBTYPE property is omitted, then the return
|
||||||
** value from [sqlite3_value_subtype()] might sometimes be zero even though
|
** value from [sqlite3_value_subtype()] might sometimes be zero even though
|
||||||
** a non-zero subtype was specified by the function argument expression.
|
** a non-zero subtype was specified by the function argument expression.
|
||||||
@ -5615,6 +5619,15 @@ SQLITE_API int sqlite3_create_window_function(
|
|||||||
** [sqlite3_result_subtype()] should avoid setting this property, as the
|
** [sqlite3_result_subtype()] should avoid setting this property, as the
|
||||||
** purpose of this property is to disable certain optimizations that are
|
** purpose of this property is to disable certain optimizations that are
|
||||||
** incompatible with subtypes.
|
** incompatible with subtypes.
|
||||||
|
**
|
||||||
|
** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
|
||||||
|
** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
|
||||||
|
** that internally orders the values provided to the first argument. The
|
||||||
|
** ordered-set aggregate SQL notation with a single ORDER BY term can be
|
||||||
|
** used to invoke this function. If the ordered-set aggregate notation is
|
||||||
|
** used on a function that lacks this flag, then an error is raised. Note
|
||||||
|
** that the ordered-set aggregate syntax is only available if SQLite is
|
||||||
|
** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
|
||||||
** </dd>
|
** </dd>
|
||||||
** </dl>
|
** </dl>
|
||||||
*/
|
*/
|
||||||
@ -5623,6 +5636,7 @@ SQLITE_API int sqlite3_create_window_function(
|
|||||||
#define SQLITE_SUBTYPE 0x000100000
|
#define SQLITE_SUBTYPE 0x000100000
|
||||||
#define SQLITE_INNOCUOUS 0x000200000
|
#define SQLITE_INNOCUOUS 0x000200000
|
||||||
#define SQLITE_RESULT_SUBTYPE 0x001000000
|
#define SQLITE_RESULT_SUBTYPE 0x001000000
|
||||||
|
#define SQLITE_SELFORDER1 0x002000000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Deprecated Functions
|
** CAPI3REF: Deprecated Functions
|
||||||
@ -5820,7 +5834,7 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
|
|||||||
** one SQL function to another. Use the [sqlite3_result_subtype()]
|
** one SQL function to another. Use the [sqlite3_result_subtype()]
|
||||||
** routine to set the subtype for the return value of an SQL function.
|
** routine to set the subtype for the return value of an SQL function.
|
||||||
**
|
**
|
||||||
** Every [application-defined SQL function] that invoke this interface
|
** Every [application-defined SQL function] that invokes this interface
|
||||||
** should include the [SQLITE_SUBTYPE] property in the text
|
** should include the [SQLITE_SUBTYPE] property in the text
|
||||||
** encoding argument when the function is [sqlite3_create_function|registered].
|
** encoding argument when the function is [sqlite3_create_function|registered].
|
||||||
** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype()
|
** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype()
|
||||||
@ -7427,9 +7441,11 @@ struct sqlite3_module {
|
|||||||
** will be returned by the strategy.
|
** will be returned by the strategy.
|
||||||
**
|
**
|
||||||
** The xBestIndex method may optionally populate the idxFlags field with a
|
** The xBestIndex method may optionally populate the idxFlags field with a
|
||||||
** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
|
** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
|
||||||
** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
|
** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
|
||||||
** assumes that the strategy may visit at most one row.
|
** output to show the idxNum has hex instead of as decimal. Another flag is
|
||||||
|
** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
|
||||||
|
** return at most one row.
|
||||||
**
|
**
|
||||||
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
|
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
|
||||||
** SQLite also assumes that if a call to the xUpdate() method is made as
|
** SQLite also assumes that if a call to the xUpdate() method is made as
|
||||||
@ -7493,7 +7509,9 @@ struct sqlite3_index_info {
|
|||||||
** [sqlite3_index_info].idxFlags field to some combination of
|
** [sqlite3_index_info].idxFlags field to some combination of
|
||||||
** these bits.
|
** these bits.
|
||||||
*/
|
*/
|
||||||
#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
|
#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */
|
||||||
|
#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */
|
||||||
|
/* in EXPLAIN QUERY PLAN */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Virtual Table Constraint Operator Codes
|
** CAPI3REF: Virtual Table Constraint Operator Codes
|
||||||
@ -8330,6 +8348,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
|||||||
#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
|
#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
|
||||||
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
|
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
|
||||||
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
|
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
|
||||||
|
#define SQLITE_TESTCTRL_GETOPT 16
|
||||||
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
|
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
|
||||||
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
|
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
|
||||||
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
|
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
|
||||||
@ -8349,7 +8368,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
|||||||
#define SQLITE_TESTCTRL_TRACEFLAGS 31
|
#define SQLITE_TESTCTRL_TRACEFLAGS 31
|
||||||
#define SQLITE_TESTCTRL_TUNE 32
|
#define SQLITE_TESTCTRL_TUNE 32
|
||||||
#define SQLITE_TESTCTRL_LOGEST 33
|
#define SQLITE_TESTCTRL_LOGEST 33
|
||||||
#define SQLITE_TESTCTRL_USELONGDOUBLE 34
|
#define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */
|
||||||
#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
|
#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -9325,6 +9344,16 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|||||||
** APIs are not strictly speaking threadsafe. If they are invoked at the
|
** APIs are not strictly speaking threadsafe. If they are invoked at the
|
||||||
** same time as another thread is invoking sqlite3_backup_step() it is
|
** same time as another thread is invoking sqlite3_backup_step() it is
|
||||||
** possible that they return invalid values.
|
** possible that they return invalid values.
|
||||||
|
**
|
||||||
|
** <b>Alternatives To Using The Backup API</b>
|
||||||
|
**
|
||||||
|
** Other techniques for safely creating a consistent backup of an SQLite
|
||||||
|
** database include:
|
||||||
|
**
|
||||||
|
** <ul>
|
||||||
|
** <li> The [VACUUM INTO] command.
|
||||||
|
** <li> The [sqlite3_rsync] utility program.
|
||||||
|
** </ul>
|
||||||
*/
|
*/
|
||||||
SQLITE_API sqlite3_backup *sqlite3_backup_init(
|
SQLITE_API sqlite3_backup *sqlite3_backup_init(
|
||||||
sqlite3 *pDest, /* Destination database handle */
|
sqlite3 *pDest, /* Destination database handle */
|
||||||
@ -10524,6 +10553,14 @@ typedef struct sqlite3_snapshot {
|
|||||||
** If there is not already a read-transaction open on schema S when
|
** If there is not already a read-transaction open on schema S when
|
||||||
** this function is called, one is opened automatically.
|
** this function is called, one is opened automatically.
|
||||||
**
|
**
|
||||||
|
** If a read-transaction is opened by this function, then it is guaranteed
|
||||||
|
** that the returned snapshot object may not be invalidated by a database
|
||||||
|
** writer or checkpointer until after the read-transaction is closed. This
|
||||||
|
** is not guaranteed if a read-transaction is already open when this
|
||||||
|
** function is called. In that case, any subsequent write or checkpoint
|
||||||
|
** operation on the database may invalidate the returned snapshot handle,
|
||||||
|
** even while the read-transaction remains open.
|
||||||
|
**
|
||||||
** The following must be true for this function to succeed. If any of
|
** The following must be true for this function to succeed. If any of
|
||||||
** the following statements are false when sqlite3_snapshot_get() is
|
** the following statements are false when sqlite3_snapshot_get() is
|
||||||
** called, SQLITE_ERROR is returned. The final value of *P is undefined
|
** called, SQLITE_ERROR is returned. The final value of *P is undefined
|
||||||
@ -10832,8 +10869,6 @@ SQLITE_API int sqlite3_deserialize(
|
|||||||
#if defined(__wasi__)
|
#if defined(__wasi__)
|
||||||
# undef SQLITE_WASI
|
# undef SQLITE_WASI
|
||||||
# define SQLITE_WASI 1
|
# define SQLITE_WASI 1
|
||||||
# undef SQLITE_OMIT_WAL
|
|
||||||
# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
|
|
||||||
# ifndef SQLITE_OMIT_LOAD_EXTENSION
|
# ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||||
# define SQLITE_OMIT_LOAD_EXTENSION
|
# define SQLITE_OMIT_LOAD_EXTENSION
|
||||||
# endif
|
# endif
|
||||||
@ -13036,6 +13071,10 @@ struct Fts5PhraseIter {
|
|||||||
** (i.e. if it is a contentless table), then this API always iterates
|
** (i.e. if it is a contentless table), then this API always iterates
|
||||||
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
|
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
|
||||||
**
|
**
|
||||||
|
** In all cases, matches are visited in (column ASC, offset ASC) order.
|
||||||
|
** i.e. all those in column 0, sorted by offset, followed by those in
|
||||||
|
** column 1, etc.
|
||||||
|
**
|
||||||
** xPhraseNext()
|
** xPhraseNext()
|
||||||
** See xPhraseFirst above.
|
** See xPhraseFirst above.
|
||||||
**
|
**
|
||||||
@ -13102,9 +13141,32 @@ struct Fts5PhraseIter {
|
|||||||
**
|
**
|
||||||
** This API can be quite slow if used with an FTS5 table created with the
|
** This API can be quite slow if used with an FTS5 table created with the
|
||||||
** "detail=none" or "detail=column" option.
|
** "detail=none" or "detail=column" option.
|
||||||
|
**
|
||||||
|
** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
|
||||||
|
** If parameter iCol is less than zero, or greater than or equal to the
|
||||||
|
** number of columns in the table, SQLITE_RANGE is returned.
|
||||||
|
**
|
||||||
|
** Otherwise, this function attempts to retrieve the locale associated
|
||||||
|
** with column iCol of the current row. Usually, there is no associated
|
||||||
|
** locale, and output parameters (*pzLocale) and (*pnLocale) are set
|
||||||
|
** to NULL and 0, respectively. However, if the fts5_locale() function
|
||||||
|
** was used to associate a locale with the value when it was inserted
|
||||||
|
** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
|
||||||
|
** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
|
||||||
|
** is set to the size in bytes of the buffer, not including the
|
||||||
|
** nul-terminator.
|
||||||
|
**
|
||||||
|
** If successful, SQLITE_OK is returned. Or, if an error occurs, an
|
||||||
|
** SQLite error code is returned. The final value of the output parameters
|
||||||
|
** is undefined in this case.
|
||||||
|
**
|
||||||
|
** xTokenize_v2:
|
||||||
|
** Tokenize text using the tokenizer belonging to the FTS5 table. This
|
||||||
|
** API is the same as the xTokenize() API, except that it allows a tokenizer
|
||||||
|
** locale to be specified.
|
||||||
*/
|
*/
|
||||||
struct Fts5ExtensionApi {
|
struct Fts5ExtensionApi {
|
||||||
int iVersion; /* Currently always set to 3 */
|
int iVersion; /* Currently always set to 4 */
|
||||||
|
|
||||||
void *(*xUserData)(Fts5Context*);
|
void *(*xUserData)(Fts5Context*);
|
||||||
|
|
||||||
@ -13146,6 +13208,15 @@ struct Fts5ExtensionApi {
|
|||||||
const char **ppToken, int *pnToken
|
const char **ppToken, int *pnToken
|
||||||
);
|
);
|
||||||
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
|
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
|
||||||
|
|
||||||
|
/* Below this point are iVersion>=4 only */
|
||||||
|
int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
|
||||||
|
int (*xTokenize_v2)(Fts5Context*,
|
||||||
|
const char *pText, int nText, /* Text to tokenize */
|
||||||
|
const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
|
||||||
|
void *pCtx, /* Context passed to xToken() */
|
||||||
|
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -13166,7 +13237,7 @@ struct Fts5ExtensionApi {
|
|||||||
** A tokenizer instance is required to actually tokenize text.
|
** A tokenizer instance is required to actually tokenize text.
|
||||||
**
|
**
|
||||||
** The first argument passed to this function is a copy of the (void*)
|
** The first argument passed to this function is a copy of the (void*)
|
||||||
** pointer provided by the application when the fts5_tokenizer object
|
** pointer provided by the application when the fts5_tokenizer_v2 object
|
||||||
** was registered with FTS5 (the third argument to xCreateTokenizer()).
|
** was registered with FTS5 (the third argument to xCreateTokenizer()).
|
||||||
** The second and third arguments are an array of nul-terminated strings
|
** The second and third arguments are an array of nul-terminated strings
|
||||||
** containing the tokenizer arguments, if any, specified following the
|
** containing the tokenizer arguments, if any, specified following the
|
||||||
@ -13190,7 +13261,7 @@ struct Fts5ExtensionApi {
|
|||||||
** argument passed to this function is a pointer to an Fts5Tokenizer object
|
** argument passed to this function is a pointer to an Fts5Tokenizer object
|
||||||
** returned by an earlier call to xCreate().
|
** returned by an earlier call to xCreate().
|
||||||
**
|
**
|
||||||
** The second argument indicates the reason that FTS5 is requesting
|
** The third argument indicates the reason that FTS5 is requesting
|
||||||
** tokenization of the supplied text. This is always one of the following
|
** tokenization of the supplied text. This is always one of the following
|
||||||
** four values:
|
** four values:
|
||||||
**
|
**
|
||||||
@ -13214,6 +13285,13 @@ struct Fts5ExtensionApi {
|
|||||||
** on a columnsize=0 database.
|
** on a columnsize=0 database.
|
||||||
** </ul>
|
** </ul>
|
||||||
**
|
**
|
||||||
|
** The sixth and seventh arguments passed to xTokenize() - pLocale and
|
||||||
|
** nLocale - are a pointer to a buffer containing the locale to use for
|
||||||
|
** tokenization (e.g. "en_US") and its size in bytes, respectively. The
|
||||||
|
** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
|
||||||
|
** which case nLocale is always 0) to indicate that the tokenizer should
|
||||||
|
** use its default locale.
|
||||||
|
**
|
||||||
** For each token in the input string, the supplied callback xToken() must
|
** For each token in the input string, the supplied callback xToken() must
|
||||||
** be invoked. The first argument to it should be a copy of the pointer
|
** be invoked. The first argument to it should be a copy of the pointer
|
||||||
** passed as the second argument to xTokenize(). The third and fourth
|
** passed as the second argument to xTokenize(). The third and fourth
|
||||||
@ -13237,6 +13315,30 @@ struct Fts5ExtensionApi {
|
|||||||
** may abandon the tokenization and return any error code other than
|
** may abandon the tokenization and return any error code other than
|
||||||
** SQLITE_OK or SQLITE_DONE.
|
** SQLITE_OK or SQLITE_DONE.
|
||||||
**
|
**
|
||||||
|
** If the tokenizer is registered using an fts5_tokenizer_v2 object,
|
||||||
|
** then the xTokenize() method has two additional arguments - pLocale
|
||||||
|
** and nLocale. These specify the locale that the tokenizer should use
|
||||||
|
** for the current request. If pLocale and nLocale are both 0, then the
|
||||||
|
** tokenizer should use its default locale. Otherwise, pLocale points to
|
||||||
|
** an nLocale byte buffer containing the name of the locale to use as utf-8
|
||||||
|
** text. pLocale is not nul-terminated.
|
||||||
|
**
|
||||||
|
** FTS5_TOKENIZER
|
||||||
|
**
|
||||||
|
** There is also an fts5_tokenizer object. This is an older, deprecated,
|
||||||
|
** version of fts5_tokenizer_v2. It is similar except that:
|
||||||
|
**
|
||||||
|
** <ul>
|
||||||
|
** <li> There is no "iVersion" field, and
|
||||||
|
** <li> The xTokenize() method does not take a locale argument.
|
||||||
|
** </ul>
|
||||||
|
**
|
||||||
|
** Legacy fts5_tokenizer tokenizers must be registered using the
|
||||||
|
** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
|
||||||
|
**
|
||||||
|
** Tokenizer implementations registered using either API may be retrieved
|
||||||
|
** using both xFindTokenizer() and xFindTokenizer_v2().
|
||||||
|
**
|
||||||
** SYNONYM SUPPORT
|
** SYNONYM SUPPORT
|
||||||
**
|
**
|
||||||
** Custom tokenizers may also support synonyms. Consider a case in which a
|
** Custom tokenizers may also support synonyms. Consider a case in which a
|
||||||
@ -13345,6 +13447,33 @@ struct Fts5ExtensionApi {
|
|||||||
** inefficient.
|
** inefficient.
|
||||||
*/
|
*/
|
||||||
typedef struct Fts5Tokenizer Fts5Tokenizer;
|
typedef struct Fts5Tokenizer Fts5Tokenizer;
|
||||||
|
typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
|
||||||
|
struct fts5_tokenizer_v2 {
|
||||||
|
int iVersion; /* Currently always 2 */
|
||||||
|
|
||||||
|
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
|
||||||
|
void (*xDelete)(Fts5Tokenizer*);
|
||||||
|
int (*xTokenize)(Fts5Tokenizer*,
|
||||||
|
void *pCtx,
|
||||||
|
int flags, /* Mask of FTS5_TOKENIZE_* flags */
|
||||||
|
const char *pText, int nText,
|
||||||
|
const char *pLocale, int nLocale,
|
||||||
|
int (*xToken)(
|
||||||
|
void *pCtx, /* Copy of 2nd argument to xTokenize() */
|
||||||
|
int tflags, /* Mask of FTS5_TOKEN_* flags */
|
||||||
|
const char *pToken, /* Pointer to buffer containing token */
|
||||||
|
int nToken, /* Size of token in bytes */
|
||||||
|
int iStart, /* Byte offset of token within input text */
|
||||||
|
int iEnd /* Byte offset of end of token within input text */
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** New code should use the fts5_tokenizer_v2 type to define tokenizer
|
||||||
|
** implementations. The following type is included for legacy applications
|
||||||
|
** that still use it.
|
||||||
|
*/
|
||||||
typedef struct fts5_tokenizer fts5_tokenizer;
|
typedef struct fts5_tokenizer fts5_tokenizer;
|
||||||
struct fts5_tokenizer {
|
struct fts5_tokenizer {
|
||||||
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
|
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
|
||||||
@ -13364,6 +13493,7 @@ struct fts5_tokenizer {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Flags that may be passed as the third argument to xTokenize() */
|
/* Flags that may be passed as the third argument to xTokenize() */
|
||||||
#define FTS5_TOKENIZE_QUERY 0x0001
|
#define FTS5_TOKENIZE_QUERY 0x0001
|
||||||
#define FTS5_TOKENIZE_PREFIX 0x0002
|
#define FTS5_TOKENIZE_PREFIX 0x0002
|
||||||
@ -13383,7 +13513,7 @@ struct fts5_tokenizer {
|
|||||||
*/
|
*/
|
||||||
typedef struct fts5_api fts5_api;
|
typedef struct fts5_api fts5_api;
|
||||||
struct fts5_api {
|
struct fts5_api {
|
||||||
int iVersion; /* Currently always set to 2 */
|
int iVersion; /* Currently always set to 3 */
|
||||||
|
|
||||||
/* Create a new tokenizer */
|
/* Create a new tokenizer */
|
||||||
int (*xCreateTokenizer)(
|
int (*xCreateTokenizer)(
|
||||||
@ -13410,6 +13540,25 @@ struct fts5_api {
|
|||||||
fts5_extension_function xFunction,
|
fts5_extension_function xFunction,
|
||||||
void (*xDestroy)(void*)
|
void (*xDestroy)(void*)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* APIs below this point are only available if iVersion>=3 */
|
||||||
|
|
||||||
|
/* Create a new tokenizer */
|
||||||
|
int (*xCreateTokenizer_v2)(
|
||||||
|
fts5_api *pApi,
|
||||||
|
const char *zName,
|
||||||
|
void *pUserData,
|
||||||
|
fts5_tokenizer_v2 *pTokenizer,
|
||||||
|
void (*xDestroy)(void*)
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Find an existing tokenizer */
|
||||||
|
int (*xFindTokenizer_v2)(
|
||||||
|
fts5_api *pApi,
|
||||||
|
const char *zName,
|
||||||
|
void **ppUserData,
|
||||||
|
fts5_tokenizer_v2 **ppTokenizer
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
63
docs/cheatsheet.md
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# Tilde Friends Cheat Sheet
|
||||||
|
|
||||||
|
Making apps for the impatient tilde friend.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- either run your own instance or use [tildefriends.net](https://www.tildefriends.net/)
|
||||||
|
- register and login
|
||||||
|
- [optional] use the `ssb` app to create yourself an SSB identity
|
||||||
|
|
||||||
|
## Development Process
|
||||||
|
|
||||||
|
1. hit the `edit` link from any app or new app URL
|
||||||
|
2. make sure the path in the text box is under your username: `/~username/app/`
|
||||||
|
3. write server-side code in `app.js`
|
||||||
|
4. click the `save` button or press the save hotkey (Alt+S or _[browser-specific modifiers]_+S)
|
||||||
|
5. see the app reload on the right side
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
- **`app.setDocument(html)`** - send HTML to the browser
|
||||||
|
- **`print(...)`** - send values to the browser's developer console
|
||||||
|
|
||||||
|
## Persistence
|
||||||
|
|
||||||
|
- **`app.localStorageGet(key)`** -> **`value`**
|
||||||
|
- **`app.localStorageSet(key, value)`**
|
||||||
|
- **`database()`**, **`shared_database(key)`**, **`my_shared_database(package, key)`**
|
||||||
|
- **`db.get(key)`** -> **`value`**
|
||||||
|
- **`db.set(key, value)`**
|
||||||
|
- **`db.exchange(key, expected, value)`** -> **`exchanged`**
|
||||||
|
- **`db.remove(key)`**
|
||||||
|
- **`db.getAll()`** -> **`[key1, ...]`**
|
||||||
|
- **`db.getLike(pattern)`** -> **`{key1: value1, ...}`**
|
||||||
|
|
||||||
|
## SSB
|
||||||
|
|
||||||
|
- **`ssb.createIdentity()`** -> **`id`**
|
||||||
|
- **`ssb.getIdentities()`** -> **`[id1, ...]`**
|
||||||
|
- **`ssb.appendMessageWithIdentity(id, content)`** -> **`message_id`**
|
||||||
|
- **`ssb.blobStore(blob)`** -> **`blob_id`**
|
||||||
|
- **`ssb.blobGet(id)`** -> **`blob`**
|
||||||
|
- **`ssb.sqlAsync(query, args, row_callback)`**
|
||||||
|
|
||||||
|
## TF-RPC
|
||||||
|
|
||||||
|
Stock helper code for calling functions across the web server and browser boundary.
|
||||||
|
|
||||||
|
- on the server: `import * as tfrpc from '/tfrpc.js';`
|
||||||
|
- in the browser: `import * as tfrpc from '/static/tfrpc.js';`
|
||||||
|
- either direction:
|
||||||
|
- register a function: `tfrpc.register(function my_function() {});`
|
||||||
|
- call a remote function: `let promise = tfrpc.rpc.my_function();`
|
||||||
|
|
||||||
|
## Share
|
||||||
|
|
||||||
|
- give out web links: [https://www.tildefriends.net/~cory/screwble/](https://www.tildefriends.net/~cory/screwble/)
|
||||||
|
- use the `Attach App` button when composing a post in [the SSB app](https://www.tildefriends.net/~core/ssb/)
|
||||||
|
|
||||||
|
## More Docs
|
||||||
|
|
||||||
|
- [api reference](https://www.tildefriends.net/~cory/api/)
|
||||||
|
- [source code](https://dev.tildefriends.net/cory/tildefriends/releases)
|
295
docs/guide.md
@ -1,209 +1,166 @@
|
|||||||
# Philosophy
|
# Tilde Friends Developer's Guide
|
||||||
|
|
||||||
Tilde Friends is a platform for making, running, and sharing web applications.
|
A Tilde Friends application starts with code that runs on a Tilde Friends server, possibly far away from where you wrote it, in a little JavaScript environment, in its own restricted process, with the only access to the outside world being the ability to send messages to the server. This document gives some recipes showing how that can be used to build a functional user-facing application in light of the unique constraints present.
|
||||||
|
|
||||||
When you visit Tilde Friends in a web browser, you are presented with a
|
## Example 1: Hello, world!
|
||||||
terminal interface, typically with a big text output box covering most of the
|
|
||||||
page and an input box at the bottom, into which text or commands can be
|
|
||||||
entered. A script runs to produce text output and consume user input.
|
|
||||||
|
|
||||||
The script is a Tilde Friends application, and it runs on the server, which
|
Of course we must start with a classic.
|
||||||
means that unlike client-side JavaScript, it can have the ability to read and
|
|
||||||
write files on the server or create network connections to other machines.
|
|
||||||
Unlike node.js or other server-side runtime environments, applications are
|
|
||||||
limited for security reasons to not interfere with each other or bring the
|
|
||||||
entire server down.
|
|
||||||
|
|
||||||
Above the terminal, an "Edit" link brings a visitor to the source code for the
|
### app.js
|
||||||
current Tilde Friends application, which they can then edit, save as their own,
|
|
||||||
and run.
|
|
||||||
|
|
||||||
# Architecture
|
```
|
||||||
|
app.setDocument('<h1 style="color: #fff">Hello, world!</h1>');
|
||||||
|
```
|
||||||
|
|
||||||
Tilde Friends is a C++ application with a JavaScript runtime that provides
|
### Output
|
||||||
restricted access to filesystem, network, and other system resources. The core
|
|
||||||
process runs a core set of scripts that implement a web server, typically
|
|
||||||
starting a new process for each visitor's session which runs scripts for the
|
|
||||||
active application and stopping it when the visitor leaves.
|
|
||||||
|
|
||||||
Only the core process has access to most system resources, but session
|
<iframe srcdoc="<h1 style="color: #fff">Hello, world!</h1>"></iframe>
|
||||||
processes can be given accesss through the core process.
|
|
||||||
|
|
||||||
Service processes are identical to session processes, but they are not tied to
|
### Explanation
|
||||||
a user session.
|
|
||||||
|
|
||||||
## Communication
|
At a glance, this might seem mundane, but for it to work:
|
||||||
|
|
||||||
In the same way that web browsers expose APIs for scripts running in the
|
- the server starts a real process for your app and loads your code into it
|
||||||
browser to modify the document, play sounds and video, and draw, Tilde Friends
|
- your code runs
|
||||||
exposes APIs for scripts running on a Tilde Friends server to interact with a
|
- `app.setDocument()` sends a message back to the server
|
||||||
visitor's web browser, read and write files on the server, and otherwise
|
- the server interprets the message and redirects it to the browser
|
||||||
interact with the world.
|
- `core/client.js` in the browser receives the message and puts your HTML into an iframe
|
||||||
|
- your HTML is presented by the browser in an iframe sandbox
|
||||||
|
|
||||||
There are several distinct classes of APIs.
|
But you don't have to think about all that. Call a function, and you see the result.
|
||||||
|
|
||||||
First, there are low-level functions exposed from C++ to JavaScript. Most of
|
## Example 2: Hit Counter
|
||||||
these are only available to the core process. These typically only go through
|
|
||||||
a basic JavaScript to C++ transition and are relatively fast and immediate.
|
|
||||||
|
|
||||||
// Displays some text to the server's console.
|
Let's take advantage of code running on the server and create a little hit counter using a key value store shared between all visitors.
|
||||||
print("Hello, world!");
|
|
||||||
|
|
||||||
There is a mechanism for communicating between processes. Functions can be
|
### app.js
|
||||||
exported and called across process boundaries. When this is done, any
|
|
||||||
arguments are serialized to a network protocol, deserialized by the other
|
|
||||||
process, the function called, and finally any return value is passed back in
|
|
||||||
the same way. Any functions referenced by the arguments or return value are
|
|
||||||
also exported and can be subsequently called across process boundaries.
|
|
||||||
Functions called across process boundaries are always asynchronous, returning a
|
|
||||||
Promise. Care must be taken for security reasons to not pass dangerous
|
|
||||||
functions ("deleteAllMydata()") to untrusted processes, and it is best for
|
|
||||||
performance reasons to minimize the data size transferred between processes.
|
|
||||||
|
|
||||||
// Send an "add" function to any other running processes. When called, it
|
```
|
||||||
// will run in this process.
|
async function main() {
|
||||||
core.broadcast({add: function(x, y) { return x + y; }});
|
let db = await shared_database('visitors');
|
||||||
|
let count = parseInt((await db.get('visitors')) ?? '0') + 1;
|
||||||
|
await db.set('visitors', count.toString());
|
||||||
|
await app.setDocument(`
|
||||||
|
<h1 style="color: #fff">Welcome, visitor #${count}!</h1>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
// Receive the above message and call the function.
|
main();
|
||||||
core.register("onMessage", function(sender, message) {
|
```
|
||||||
message.add(3, 4).then(x => terminal.print(x.toString()));
|
|
||||||
|
### Output
|
||||||
|
|
||||||
|
<iframe srcdoc="<h1 style="color: #fff">Welcome, visitor #1!</h1>"></iframe>
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
|
||||||
|
Just as pure browser apps have access to `localStorage`, Tilde Friends apps have access to key-value storage on the server.
|
||||||
|
|
||||||
|
The interface is a bit clunky and will likely change someday, but this example gets a database object, from which you can get and set string values by key. There are various on `shared_database` that let you store data that is private to the user or shared by different criteria.
|
||||||
|
|
||||||
|
Also, even though any browser-side code is sandboxed, it is allowed to access browser local storage by going through Tilde Friends API, because sometimes that is useful.
|
||||||
|
|
||||||
|
## Example 3: Files
|
||||||
|
|
||||||
|
Suppose you don't want to create your entire app in a single server-side file as we've done with the previous examples. There are some tools to allow you to begin to organize.
|
||||||
|
|
||||||
|
### app.js
|
||||||
|
|
||||||
|
```
|
||||||
|
async function main() {
|
||||||
|
let html = utf8Decode(await getFile('index.html'));
|
||||||
|
app.setDocument(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
```
|
||||||
|
|
||||||
|
### index.html
|
||||||
|
|
||||||
|
```
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script type="module" src="script.js"></script>
|
||||||
|
</head>
|
||||||
|
<body style="color: #fff">
|
||||||
|
<h1>File Test</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
### script.js
|
||||||
|
|
||||||
|
```
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
document.body.appendChild(document.createTextNode('Hello, world');
|
||||||
});
|
});
|
||||||
|
```
|
||||||
|
|
||||||
Finally, there is a core web interface that runs on the client's browser that
|
### Output
|
||||||
extends access to a running Tilde Friends script.
|
|
||||||
|
|
||||||
// Displays a message in the client's browser.
|
<iframe srcdoc="<body style="color: #fff"><h1>File Test</h1>Hello, world!</body>"></iframe>
|
||||||
terminal.print("Hello, world!");
|
|
||||||
|
|
||||||
## API Documentation
|
### Explanation
|
||||||
|
|
||||||
The Tilde Friends API is very much evolving.
|
On the server, `utf8Decode(await getFile(fileName))` lets you load a file from your app. In the browser, your app files are made available by HTTP, so you can `<script src="my_script.js"></script>` and such to access them.
|
||||||
|
|
||||||
All currently registered methods can be explored in the
|
## Example 4: Remote Procedure Call
|
||||||
[documentation](https://www.tildefriends.net/~cory/documentation) app.
|
|
||||||
|
|
||||||
All browser-facing methods are implemented in [client.js](core/client.js).
|
While making calls between the client and the server, it is possible to pass functions across that boundary. `tfrpc.js` is a tiny script which builds on that feature to try to hide some of the complexities.
|
||||||
Most process-related methods are implemented in [core.js](core/core.js).
|
|
||||||
|
|
||||||
Higher-level behaviors are often implemented within library-style apps
|
### app.js
|
||||||
themselves and are beyond the scope of this document.
|
|
||||||
|
|
||||||
### Terminal
|
```
|
||||||
|
import * as tf from '/tfrpc.js';
|
||||||
|
|
||||||
All interaction with a human user is through a terminal-like interface. Though
|
function sum() {
|
||||||
it is somewhat limiting, it makes simple things easy, and it is possible to
|
let s = 0
|
||||||
construct complicated interfaces by creating and interacting with an iframe.
|
for (let x of arguments) {
|
||||||
|
s += x;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
tf.register(sum);
|
||||||
|
|
||||||
#### terminal.print(arguments...)
|
async function main() {
|
||||||
|
app.setDocument(utf8Decode(await getFile('index.html')));
|
||||||
|
}
|
||||||
|
main();
|
||||||
|
```
|
||||||
|
|
||||||
Print to the terminal. Arguments and lists are recursively expanded. Numerous
|
### index.html
|
||||||
special values are supported as implemented in client.cs.
|
|
||||||
|
|
||||||
// Create a link.
|
```
|
||||||
terminal.print({href: "http://www.tildefriends.net/", value: "Tilde Friends!"});
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1 id='result'>Calculating...</h1>
|
||||||
|
</body>
|
||||||
|
<script type="module" src="script.js"></script>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
// Create an iframe.
|
### script.js
|
||||||
terminal.print({iframe: "<b>Hello, world!</b>", width: 640, height: 480});
|
|
||||||
|
|
||||||
// Use style.
|
```
|
||||||
terminal.print({style: "color: #f00", value: "Hello, world!"});
|
import * as tf from '/static/tfrpc.js';
|
||||||
|
|
||||||
// Create a link that when clicked will act as if the user typed a command.
|
window.addEventListener('load', async function() {
|
||||||
terminal.print({command: "exit", value: "Get out of here."});
|
document.getElementById('result').innerText = await tf.rpc.sum(1, 2, 3);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
#### terminal.clear()
|
### Output
|
||||||
|
|
||||||
Clears the terminal output.
|
<iframe srcdoc="<body style="color: #fff"><h1>6</h1></body>"></iframe>
|
||||||
|
|
||||||
#### terminal.readLine()
|
### Explanation
|
||||||
|
|
||||||
Read a line of input from the user.
|
Here the browser makes an asynchronous call to the server to do some basic math and update its DOM with the result.
|
||||||
|
|
||||||
#### terminal.setEcho(echo)
|
With your favorite Vue/Lit/React/... library on the client-side and your favorite Tilde Friends API calls registered with tfrpc, it becomes pretty easy to start extracting interesting information from, say, SQL queries over Secure Scuttlebutt data, and generating complicated, dynamic user interface. These are the building blocks I used to make the current Tilde Friends SSB client interface.
|
||||||
|
|
||||||
Controls whether the terminal will automatically echo user input. Defaults to true.
|
## Conclusion
|
||||||
|
|
||||||
#### terminal.setPrompt(prompt)
|
Tilde Friends is currently a pile of all the parts that I thought I needed to build interesting web applications, tied together by code that tries to walk the fine line between being secure enough to let us safely run code on the same device and being usable enough that you can open a tab in your browser and start building just by typing code.
|
||||||
|
|
||||||
Sets the terminal prompt. The default is ">".
|
I don't claim it thoroughly accomplishes either yet, but I believe it is at a stage where it is showing how promising this approach can be, and I am excited for you to take it for a spin and share.
|
||||||
|
|
||||||
#### terminal.setTitle(title)
|
|
||||||
|
|
||||||
Sets the browser window/tab title.
|
|
||||||
|
|
||||||
#### terminal.split(terminalList)
|
|
||||||
|
|
||||||
Reconfigures the terminal layout, potentially into multiple split panes.
|
|
||||||
|
|
||||||
terminal.split([
|
|
||||||
{
|
|
||||||
type: "horizontal",
|
|
||||||
children: [
|
|
||||||
{name: "left", basis: "2in", grow: 0, shrink: 0},
|
|
||||||
{name: "middle", grow: 1},
|
|
||||||
{name: "right", basis: "2in", grow: 0, shrink: 0},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
#### terminal.select(name)
|
|
||||||
|
|
||||||
Directs subsequent output to the named terminal.
|
|
||||||
|
|
||||||
#### terminal.postMessageToIframe(iframeName, message)
|
|
||||||
|
|
||||||
Sends a message to the iframe that was created with the given name, using the
|
|
||||||
browser's window.postMessage.
|
|
||||||
|
|
||||||
### Database
|
|
||||||
|
|
||||||
Tilde Friends uses lmdb as a basic key value store. Keys and values are all
|
|
||||||
expected to be of type String. Each application gets its own isolated
|
|
||||||
database.
|
|
||||||
|
|
||||||
#### database.get(key)
|
|
||||||
|
|
||||||
Retrieve the database value associated with the given key.
|
|
||||||
|
|
||||||
#### database.set(key, value)
|
|
||||||
|
|
||||||
Sets the database value for the given key, overwriting any existing value.
|
|
||||||
|
|
||||||
#### database.remove(key)
|
|
||||||
|
|
||||||
Remove the database entry for the given key.
|
|
||||||
|
|
||||||
#### database.getAlll()
|
|
||||||
|
|
||||||
Retrieve a list of all key names.
|
|
||||||
|
|
||||||
### Network
|
|
||||||
|
|
||||||
Network access is generally not extended to untrusted users.
|
|
||||||
|
|
||||||
It is necessary to grant network permissions to an app owner through the
|
|
||||||
administration app.
|
|
||||||
|
|
||||||
Apps that require network access must declare it like this:
|
|
||||||
|
|
||||||
//! { "permissions": ["network"] }
|
|
||||||
|
|
||||||
#### network.newConnection()
|
|
||||||
|
|
||||||
Creates a Connection object.
|
|
||||||
|
|
||||||
#### connection.connect(host, port)
|
|
||||||
|
|
||||||
Opens a TCP connection to host:port.
|
|
||||||
|
|
||||||
#### connection.read(readCallback)
|
|
||||||
|
|
||||||
Begins reading and calls readCallback(data) for all data received.
|
|
||||||
|
|
||||||
#### connection.write(data)
|
|
||||||
|
|
||||||
Writes data to the connection.
|
|
||||||
|
|
||||||
#### connection.close()
|
|
||||||
|
|
||||||
Closes the connection.
|
|
||||||
|
19
docs/release.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Release Checklist
|
||||||
|
|
||||||
|
- make sure ci is passing
|
||||||
|
- run the tests
|
||||||
|
- format + prettier
|
||||||
|
- update metadata/en-US/changelogs
|
||||||
|
- git tag
|
||||||
|
- push
|
||||||
|
- make dist
|
||||||
|
- make a release on gitea
|
||||||
|
- upload the artifacts
|
||||||
|
- nix
|
||||||
|
- comment out the hash in default.nix
|
||||||
|
- update the version
|
||||||
|
- run `nix-build`
|
||||||
|
- update the hash
|
||||||
|
- bump the versions in GNUmakefile for the next release
|
||||||
|
- make
|
||||||
|
- commit
|
64
docs/vision.md
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Tilde Friends Vision
|
||||||
|
|
||||||
|
Tilde Friends is a tool for making and sharing.
|
||||||
|
|
||||||
|
It is both a peer-to-peer social network client, participating in Secure
|
||||||
|
Scuttlebutt, and an environment for creating and running web applications.
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
|
This is a thing that I wanted to exist and wanted to work on. No other reason.
|
||||||
|
There is not a business model. I believe it is interesting and unique.
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
|
||||||
|
1. Make it **easy and fun** to run all sorts of web applications.
|
||||||
|
|
||||||
|
2. Provide **security** that is easy to understand and protects your data.
|
||||||
|
|
||||||
|
3. Make **creating and sharing** web applications accessible to anyone with a
|
||||||
|
browser.
|
||||||
|
|
||||||
|
## Ways to Use Tilde Friends
|
||||||
|
|
||||||
|
1. **Social Network User**: This is a social network first. You are just here,
|
||||||
|
because your friends are. Or you like how we limit your message length or
|
||||||
|
short videos or whatever the trend is. If you are ambitious, you click links
|
||||||
|
and see interactive experiences (apps) that you wouldn't see elsewhere.
|
||||||
|
|
||||||
|
2. **Web Visitor**: You get links from a friend to meeting invites, polls, games,
|
||||||
|
lists, wiki pages, ..., and you interact with them as though they were
|
||||||
|
cloud-hosted by a megacorporation. They just work, and you don't think twice.
|
||||||
|
|
||||||
|
3. **Group leader**: You host or use a small public instance, installing apps for
|
||||||
|
a group of friends to use as web visitors.
|
||||||
|
|
||||||
|
4. **Developer**: You like to write code and make or improve apps for fun or to
|
||||||
|
solve problems. When you encounter a Tilde Friends app on a strange server,
|
||||||
|
you know you can trivially modify it or download it to your own instance.
|
||||||
|
|
||||||
|
## Future Goals / Endgame
|
||||||
|
|
||||||
|
1. Mobile apps. This can run on your old phone. Maybe you won't be hosting
|
||||||
|
the web interface publicly, but you can sync, install and edit apps, and
|
||||||
|
otherwise get the full experience from a tiny touch screen.
|
||||||
|
|
||||||
|
2. The universal application runtime. The web browser is the universal
|
||||||
|
platform, but even for the simplest application that you might want to host
|
||||||
|
for your friends, cloud hosting, containers, and complicated dependencies might
|
||||||
|
all enter the mix. Tilde Friends, though it is yet another thing to host,
|
||||||
|
includes everything you need out of the box to run a vast variety of interesting
|
||||||
|
apps.
|
||||||
|
|
||||||
|
Tilde Friends will be built out, gradually providing safe access to host
|
||||||
|
resources and client resources the same way web browsers extended access to
|
||||||
|
resources like GPU, persistent storage, cameras, ... over the years.
|
||||||
|
|
||||||
|
Not much effort has been put forward yet to having a robust, long-lasting API,
|
||||||
|
but since the client side longevity is already handled by web browsers, it
|
||||||
|
seems possible that the server-side API can be managed in a similar way.
|
||||||
|
|
||||||
|
3. An awesome development environment. Right now it runs JavaScript from the
|
||||||
|
first embeddable text editor I could poorly configure enough to edit code,
|
||||||
|
but it could incorporate a debugger, source control integration a la ssb-git,
|
||||||
|
merge tools, and transpiling from all sorts of different languages.
|
7
metadata/en-US/changelogs/24.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
* Reworked Android to launch its sandbox processes the prescribed way so that
|
||||||
|
a Google Play-shippable android .aab is possible.
|
||||||
|
* Reworked the build to generate what F-Droid wants, too.
|
||||||
|
* Updated libbacktrace.
|
||||||
|
* Updated CodeMirror.
|
||||||
|
* Updated Android NDK.
|
||||||
|
* Enabled LTO for smaller code sizes.
|
12
metadata/en-US/changelogs/26.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
* Took an initial whack at encouraging internet-based discovery of open peers.
|
||||||
|
* Added settings to control whether replication, room, peer exchange, and account registration are allowed.
|
||||||
|
* Implemented prompt() on Android.
|
||||||
|
* Fixed some incorrect cross-thread use of the main JS context.
|
||||||
|
* Fixed yet another incorrect use of the DB from the main thread, from an RPC that isn't ever hit. Hmm.
|
||||||
|
* Minor admin layout fixes.
|
||||||
|
* Added c-ares for TXT record lookups.
|
||||||
|
* Latest libsodium-stable.
|
||||||
|
* Latest libbacktrace.
|
||||||
|
* Latest CodeMirror.
|
||||||
|
* Updated to Lit 3.2.0.
|
||||||
|
* Updated sqlite to 3.46.1.
|
11
metadata/en-US/changelogs/27.txt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
* Fix WebView localStorage on some Android versions.
|
||||||
|
* Fix viewing apps by blob URL.
|
||||||
|
* Let admin users use the server identity.
|
||||||
|
* Time out SHS connections that don't handshake.
|
||||||
|
* Add an SQL index on message type.
|
||||||
|
* Build an AppImage.
|
||||||
|
* Improve vote layout.
|
||||||
|
* Updated CodeMirror to latest.
|
||||||
|
* Updated OpenSSL to 3.3.2.
|
||||||
|
* Updated libuv to 1.49.0.
|
||||||
|
* Updated c-ares to 1.33.1.
|
19
metadata/en-US/changelogs/29.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
* Command-line publishing.
|
||||||
|
* SSB replication improvements.
|
||||||
|
* Disallow rich text paste more.
|
||||||
|
* identity app lets you change the server account.
|
||||||
|
* SSB profile icons stretching.
|
||||||
|
* Fixed iPhone app missing data.
|
||||||
|
* Added an initiate sync button.
|
||||||
|
* Fixed the AppImage.
|
||||||
|
* Flatpak WIP.
|
||||||
|
* Android compatibility fixes.
|
||||||
|
* Updates:
|
||||||
|
* CodeMirror
|
||||||
|
* CommonMark 0.31.2
|
||||||
|
* Lit 3.2.1
|
||||||
|
* OpenSSL 3.4.0
|
||||||
|
* c-ares 1.34.2
|
||||||
|
* libbacktrace
|
||||||
|
* libuv 1.49.2
|
||||||
|
* sqlite 3.47.0
|
3
metadata/en-US/full_description.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Tilde Friends is both a peer-to-peer social network client, participating in
|
||||||
|
Secure Scuttlebutt, as well as a platform for writing and running web
|
||||||
|
applications.
|
BIN
metadata/en-US/images/icon.png
Normal file
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 298 KiB |
After Width: | Height: | Size: 275 KiB |
After Width: | Height: | Size: 186 KiB |
1
metadata/en-US/short_description.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
A tool for making and sharing
|
1
metadata/en-US/title.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Tilde Friends
|
4
package-lock.json
generated
@ -11,7 +11,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.2.5",
|
"version": "3.3.3",
|
||||||
|
"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,15 +1,13 @@
|
|||||||
<?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="20"
|
android:versionCode="30"
|
||||||
android:versionName="0.0.20">
|
android:versionName="0.0.25-wip">
|
||||||
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="34"/>
|
<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
|
||||||
android:label="Tilde Friends"
|
android:label="Tilde Friends"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true">
|
||||||
android:debuggable="true"
|
|
||||||
android:extractNativeLibs="true">
|
|
||||||
<meta-data android:name="android.max_aspect" android:value="2.1"/>
|
<meta-data android:name="android.max_aspect" android:value="2.1"/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".TildeFriendsActivity"
|
android:name=".TildeFriendsActivity"
|
||||||
@ -21,5 +19,10 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<service
|
||||||
|
android:name=".TildeFriendsSandboxService"
|
||||||
|
android:exported="false"
|
||||||
|
android:isolatedProcess="true"
|
||||||
|
android:process=":sandbox"/>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
5
src/android/BundleConfig.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"optimizations" : {
|
||||||
|
"uncompress_native_libraries" : {}
|
||||||
|
}
|
||||||
|
}
|
6
src/android/build.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<project>
|
||||||
|
<target name="clean"></target>
|
||||||
|
<target name="release">
|
||||||
|
<echo>Creating ../../../out/apk/TildeFriends-release.fdroid.unsigned.apk for release.</echo>
|
||||||
|
</target>
|
||||||
|
</project>
|
@ -3,15 +3,21 @@ package com.unprompted.tildefriends;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.DownloadManager;
|
import android.app.DownloadManager;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.CountDownTimer;
|
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.os.FileObserver;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.os.SystemClock;
|
import android.text.InputType;
|
||||||
import android.os.strictmode.Violation;
|
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
@ -29,39 +35,41 @@ import android.webkit.WebChromeClient;
|
|||||||
import android.webkit.WebResourceRequest;
|
import android.webkit.WebResourceRequest;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
import android.widget.Button;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.InputStream;
|
import java.io.OutputStream;
|
||||||
import java.lang.Process;
|
|
||||||
import java.lang.Thread;
|
|
||||||
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 {
|
||||||
|
static TildeFriendsActivity s_activity;
|
||||||
TildeFriendsWebView web_view;
|
TildeFriendsWebView web_view;
|
||||||
String base_url;
|
String base_url;
|
||||||
Process process;
|
String port_file_path;
|
||||||
Thread thread;
|
Thread server_thread;
|
||||||
|
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;
|
||||||
private float touch_down_y;
|
private float touch_down_y;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Log.w("tildefriends", "Calling system.loadLibrary().");
|
||||||
|
System.loadLibrary("tildefriends");
|
||||||
|
Log.w("tildefriends", "system.loadLibrary() completed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static native int tf_server_main(String files_dir, String apk_path, String out_port_file_path, ConnectivityManager connectivity_manager);
|
||||||
|
public static native int tf_sandbox_main(int pipe_fd);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
s_activity = this;
|
||||||
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
|
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
|
||||||
.detectLeakedClosableObjects()
|
.detectLeakedClosableObjects()
|
||||||
.penaltyLog()
|
.penaltyLog()
|
||||||
@ -76,80 +84,37 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
Log.w("tildefriends", String.format("getPackageResourcePath() is %s", getPackageResourcePath().toString()));
|
Log.w("tildefriends", String.format("getPackageResourcePath() is %s", getPackageResourcePath().toString()));
|
||||||
Log.w("tildefriends", String.format("nativeLibraryDir is %s", getApplicationInfo().nativeLibraryDir));
|
Log.w("tildefriends", String.format("nativeLibraryDir is %s", getApplicationInfo().nativeLibraryDir));
|
||||||
|
|
||||||
String port_file_path = getFilesDir().toString() + "/port.txt";
|
port_file_path = getFilesDir().toString() + "/port.txt";
|
||||||
new File(port_file_path).delete();
|
new File(port_file_path).delete();
|
||||||
base_url = "http://127.0.0.1:12345/";
|
base_url = "http://127.0.0.1:12345/";
|
||||||
|
|
||||||
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());
|
||||||
try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
|
observer = make_file_observer(getFilesDir().toString(), port_file_path);
|
||||||
Paths.get(getFilesDir().toString()).register(
|
observer.startWatching();
|
||||||
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...");
|
||||||
String exe = getApplicationInfo().nativeLibraryDir + "/tildefriends.so";
|
server_thread = new Thread(new Runnable() {
|
||||||
ProcessBuilder builder = new ProcessBuilder(exe, "run", "-z", getPackageResourcePath().toString(), "-a", "out_http_port_file=" + port_file_path, "-p", "0");
|
@Override
|
||||||
Log.w("tildefriends", "files = " + getFilesDir().toString());
|
public void run() {
|
||||||
Log.w("tildefriends", "exe = " + exe);
|
Log.w("tildefriends", "Calling tf_server_main.");
|
||||||
builder.directory(getFilesDir());
|
int result = tf_server_main(
|
||||||
builder.inheritIO();
|
getFilesDir().toString(),
|
||||||
try {
|
getPackageResourcePath().toString(),
|
||||||
process = builder.start();
|
port_file_path,
|
||||||
} catch (java.io.IOException e) {
|
(ConnectivityManager)getApplicationContext().getSystemService(CONNECTIVITY_SERVICE));
|
||||||
Log.w("tildefriends", "IOException starting process: " + e.toString());
|
Log.w("tildefriends", "tf_server_main returned " + result + ".");
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
server_thread.start();
|
||||||
|
|
||||||
web_view.getSettings().setJavaScriptEnabled(true);
|
web_view.getSettings().setJavaScriptEnabled(true);
|
||||||
web_view.getSettings().setDatabaseEnabled(true);
|
web_view.getSettings().setDatabaseEnabled(true);
|
||||||
web_view.getSettings().setDomStorageEnabled(true);
|
web_view.getSettings().setDomStorageEnabled(true);
|
||||||
|
|
||||||
|
set_database_path();
|
||||||
|
|
||||||
web_view.setDownloadListener(new DownloadListener() {
|
web_view.setDownloadListener(new DownloadListener() {
|
||||||
public void onDownloadStart(String url, String userAgent, String content_disposition, String mime_type, long content_length) {
|
public void onDownloadStart(String url, String userAgent, String content_disposition, String mime_type, long content_length) {
|
||||||
Log.w("tildefriends", "Let's download: " + url + " (" + content_disposition + ")");
|
Log.w("tildefriends", "Let's download: " + url + " (" + content_disposition + ")");
|
||||||
@ -184,7 +149,24 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
|
|
||||||
web_view.setWebChromeClient(new WebChromeClient() {
|
web_view.setWebChromeClient(new WebChromeClient() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
|
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
|
||||||
|
new AlertDialog.Builder(view.getContext())
|
||||||
|
.setTitle("Tilde Friends")
|
||||||
|
.setMessage(message)
|
||||||
|
.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
result.confirm();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
|
||||||
new AlertDialog.Builder(view.getContext())
|
new AlertDialog.Builder(view.getContext())
|
||||||
.setTitle("Tilde Friends")
|
.setTitle("Tilde Friends")
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
@ -208,15 +190,27 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
|
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
|
||||||
|
EditText input = new EditText(view.getContext());
|
||||||
|
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
|
input.setText(defaultValue);
|
||||||
|
|
||||||
new AlertDialog.Builder(view.getContext())
|
new AlertDialog.Builder(view.getContext())
|
||||||
.setTitle("Tilde Friends")
|
.setTitle("Tilde Friends")
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
.setView(input)
|
||||||
|
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
||||||
{
|
{
|
||||||
public void onClick(DialogInterface dialog, int which)
|
public void onClick(DialogInterface dialog, int which)
|
||||||
{
|
{
|
||||||
result.confirm();
|
result.confirm(input.getText().toString());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
result.cancel();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.create()
|
.create()
|
||||||
@ -266,13 +260,8 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onDestroy()
|
protected void onDestroy()
|
||||||
{
|
{
|
||||||
if (process != null) {
|
|
||||||
Log.w("tildefriends", "Killing process.");
|
|
||||||
process.destroyForcibly();
|
|
||||||
Log.w("tildefriends", "Process killed.");
|
|
||||||
process = null;
|
|
||||||
}
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
s_activity = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -351,11 +340,14 @@ 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))) {
|
||||||
return Integer.parseInt(reader.readLine());
|
String line = 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) {
|
||||||
e.printStackTrace();
|
Log.w("tildefriends", "Port file does not yet exist.");
|
||||||
} catch (java.io.IOException e) {
|
} catch (java.io.IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -374,4 +366,87 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
web_view.setVisibility(View.VISIBLE);
|
web_view.setVisibility(View.VISIBLE);
|
||||||
text_view.setVisibility(View.GONE);
|
text_view.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void start_sandbox(int pipe_fd) {
|
||||||
|
Log.w("tildefriends", "starting service with fd: " + pipe_fd);
|
||||||
|
Intent intent = new Intent(s_activity, TildeFriendsSandboxService.class);
|
||||||
|
s_activity.service_connection = new ServiceConnection() {
|
||||||
|
@Override
|
||||||
|
public void onBindingDied(ComponentName name) {
|
||||||
|
Log.w("tildefriends", "onBindingDied");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNullBinding(ComponentName name) {
|
||||||
|
Log.w("tildefriends", "onNullBinding");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected(ComponentName name, IBinder binder) {
|
||||||
|
Log.w("tildefriends", "onServiceConnected");
|
||||||
|
Parcel data = Parcel.obtain();
|
||||||
|
ParcelFileDescriptor pfd = ParcelFileDescriptor.adoptFd(pipe_fd);
|
||||||
|
data.writeParcelable(pfd, 0);
|
||||||
|
try {
|
||||||
|
binder.transact(TildeFriendsSandboxService.START_CALL, data, null, IBinder.FLAG_ONEWAY);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.w("tildefriends", "RemoteException");
|
||||||
|
} finally {
|
||||||
|
data.recycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
Log.w("tildefriends", "onServiceDisconnected");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
s_activity.bindService(intent, s_activity.service_connection, BIND_AUTO_CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stop_sandbox() {
|
||||||
|
Log.w("tildefriends", "stop_sandbox");
|
||||||
|
if (s_activity.service_connection != null) {
|
||||||
|
s_activity.unbindService(s_activity.service_connection);
|
||||||
|
s_activity.service_connection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
private void set_database_path()
|
||||||
|
{
|
||||||
|
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
|
||||||
|
web_view.getSettings().setDatabasePath(getDatabasePath("webview").getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
package com.unprompted.tildefriends;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class TildeFriendsSandboxService extends Service {
|
||||||
|
public static final int START_CALL = IBinder.FIRST_CALL_TRANSACTION;
|
||||||
|
|
||||||
|
Thread thread;
|
||||||
|
|
||||||
|
public int onStartCommand(Intent intent, int flags, int start_id) {
|
||||||
|
Log.w("tildefriends", "TildeFriendsSandboxService: onStartCommand");
|
||||||
|
return super.onStartCommand(intent, flags, start_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDestroy() {
|
||||||
|
Log.w("tildefriends", "TildeFriendsSandboxService: onDestroy");
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void start_thread(int pipe_fd) {
|
||||||
|
thread = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Log.w("tildefriends", "Calling tf_sandbox_main.");
|
||||||
|
int result = TildeFriendsActivity.tf_sandbox_main(pipe_fd);
|
||||||
|
Log.w("tildefriends", "tf_sandbox_main returned " + result + ".");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return new Binder() {
|
||||||
|
@Override
|
||||||
|
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
|
||||||
|
if (code == START_CALL) {
|
||||||
|
ParcelFileDescriptor pfd = read_pfd(data);
|
||||||
|
if (pfd != null) {
|
||||||
|
Log.w("tildefriends", "fd is " + pfd.getFd());
|
||||||
|
start_thread(pfd.detachFd());
|
||||||
|
try {
|
||||||
|
pfd.close();
|
||||||
|
} catch (java.io.IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
static private ParcelFileDescriptor read_pfd(Parcel data) {
|
||||||
|
return data.readParcelable(ParcelFileDescriptor.class.getClassLoader());
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@ package com.unprompted.tildefriends;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
public class TildeFriendsWebView extends android.webkit.WebView {
|
public class TildeFriendsWebView extends android.webkit.WebView {
|
||||||
boolean overscrolledY = false;
|
boolean overscrolledY = false;
|
||||||
|
@ -1,78 +1,55 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="72dp"
|
android:width="65dp"
|
||||||
android:height="72dp"
|
android:height="65dp"
|
||||||
android:viewportWidth="72"
|
android:viewportWidth="61"
|
||||||
android:viewportHeight="72">
|
android:viewportHeight="65">
|
||||||
<path
|
<path
|
||||||
android:pathData="M36,36m-23,0a23,23 0,1 1,46 0a23,23 0,1 1,-46 0"
|
android:pathData="M6,0h49a8,8 45,0 1,8 8v49a8,8 135,0 1,-8 8H6a8,8 45,0 1,-8 -8V8a8,8 135,0 1,8 -8Z"
|
||||||
android:fillColor="#FCEA2B"/>
|
android:strokeWidth=".712717"
|
||||||
|
android:fillColor="#0af"
|
||||||
|
android:fillAlpha="1"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M45.331,38.564c3.963,0 7.178,-2.862 7.178,-6.389c0,-1.765 0.447,-3.529 -0.852,-4.685s-4.345,-1.704 -6.326,-1.704c-2.357,0 -5.143,0.143 -6.451,1.704c-0.893,1.065 -0.727,3.253 -0.727,4.685C38.153,35.702 41.366,38.564 45.331,38.564z"
|
android:pathData="m1.6762,36.6891v-4.0039q2.0703,-2.3438 5.4297,-2.3438 1.1719,0 2.4609,0.3516 1.2891,0.332 3.6719,1.3477 1.3477,0.5664 2.0117,0.7422 0.6836,0.1758 1.3672,0.1758 1.2695,0 2.6172,-0.7617 1.3672,-0.7617 2.4219,-1.9141v4.1406q-1.25,1.1719 -2.5391,1.6992 -1.2695,0.5273 -2.8711,0.5273 -1.1719,0 -2.2461,-0.2734 -1.0547,-0.2734 -3.3789,-1.3086 -2.3047,-1.0352 -3.8477,-1.0352 -1.25,0 -2.3633,0.5469 -1.0938,0.5273 -2.7344,2.1094z"
|
||||||
android:fillColor="#3F3F3F"/>
|
android:fillColor="#000000"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M25.738,38.564c3.963,0 7.178,-2.862 7.178,-6.389c0,-1.765 0.447,-3.529 -0.852,-4.685s-4.345,-1.704 -6.326,-1.704c-2.357,0 -5.143,0.143 -6.451,1.704c-0.893,1.065 -0.727,3.253 -0.727,4.685C18.56,35.702 21.773,38.564 25.738,38.564z"
|
android:pathData="M42.4653,32.2273m-16.7723,0a16.7723,16.7723 0,1 1,33.5446 0a16.7723,16.7723 0,1 1,-33.5446 0"
|
||||||
android:fillColor="#3F3F3F"/>
|
android:fillColor="#fcea2b"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M35.887,36.056m-23,0a23,23 0,1 1,46 0a23,23 0,1 1,-46 0"
|
android:pathData="M49.2697,34.097c2.8899,0 5.2344,-2.0871 5.2344,-4.6591 0,-1.2871 0.3267,-2.5742 -0.6213,-3.4164 -0.9473,-0.843 -3.1685,-1.2426 -4.6131,-1.2426 -1.7188,0 -3.7504,0.1043 -4.7043,1.2426 -0.6519,0.7766 -0.5302,2.3722 -0.5302,3.4164 0,2.572 2.343,4.6591 5.2344,4.6591zM34.9819,34.097c2.8899,0 5.2351,-2.0871 5.2351,-4.6591 0,-1.2871 0.326,-2.5742 -0.6213,-3.4164 -0.948,-0.843 -3.1685,-1.2426 -4.6138,-1.2426 -1.7181,0 -3.7497,0.1043 -4.7043,1.2426 -0.6512,0.7766 -0.5302,2.3722 -0.5302,3.4164 0,2.572 2.343,4.6591 5.2344,4.6591z"
|
||||||
|
android:fillColor="#3f3f3f"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M42.3829,32.2681m-16.7723,0a16.7723,16.7723 0,1 1,33.5446 0a16.7723,16.7723 0,1 1,-33.5446 0"
|
||||||
android:strokeLineJoin="round"
|
android:strokeLineJoin="round"
|
||||||
android:strokeWidth="2"
|
android:strokeWidth="2"
|
||||||
android:fillColor="#00000000"
|
android:fillColor="#00000000"
|
||||||
android:strokeColor="#000000"
|
android:strokeColor="#000"
|
||||||
android:strokeLineCap="round"/>
|
android:strokeLineCap="round"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M45.702,44.862c-6.574,3.525 -14.045,3.658 -19.629,0"
|
android:pathData="M49.5403,38.6897c-4.794,2.5705 -10.242,2.6675 -14.3148,0M29.983,28.1903s-0.695,6.2349 5.0025,5.774c1.9106,-0.1546 5.7004,-0.474 5.7369,-6.0832 0.0036,-0.509 -0.0051,-1.1668 -0.5907,-1.9179 -0.7766,-0.9969 -2.6048,-1.4373 -7.2522,-1.037 0,0 -2.5129,-0.0729 -2.8965,3.264z"
|
||||||
android:strokeLineJoin="round"
|
android:strokeLineJoin="round"
|
||||||
android:strokeWidth="2"
|
android:strokeWidth="2"
|
||||||
android:fillColor="#00000000"
|
android:fillColor="#00000000"
|
||||||
android:strokeColor="#000000"
|
android:strokeColor="#000"
|
||||||
android:strokeLineCap="round"/>
|
android:strokeLineCap="round"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M18.883,30.464c0,0 -0.953,8.551 6.861,7.918c2.62,-0.212 7.816,-0.651 7.867,-8.343c0.005,-0.698 -0.008,-1.599 -0.811,-2.63c-1.065,-1.367 -3.572,-1.971 -9.945,-1.422C22.855,25.988 19.409,25.889 18.883,30.464z"
|
android:pathData="m30.0341,27.8016 l-0.3158,-2.459 2.7951,-0.3843M54.6733,28.1903s0.695,6.2349 -5.0025,5.774c-1.9106,-0.1546 -5.7004,-0.474 -5.7376,-6.0832 -0.0029,-0.509 0.0058,-1.1668 0.5914,-1.9179 0.7766,-0.9969 2.6048,-1.4373 7.2522,-1.037 0,0 2.5129,-0.0729 2.8965,3.264z"
|
||||||
android:strokeLineJoin="round"
|
android:strokeLineJoin="round"
|
||||||
android:strokeWidth="2"
|
android:strokeWidth="2"
|
||||||
android:fillColor="#00000000"
|
android:fillColor="#00000000"
|
||||||
android:strokeColor="#000000"
|
android:strokeColor="#000"
|
||||||
android:strokeLineCap="round"/>
|
android:strokeLineCap="round"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M18.953,29.931l-0.433,-3.371l3.833,-0.528"
|
android:pathData="M39.1874,25.2383s3.0073,1.8479 6.3129,0M40.6685,28.813s1.6058,-2.7353 3.3078,0M54.6172,27.803l0.3158,-2.4582 -2.7951,-0.385"
|
||||||
android:strokeLineJoin="round"
|
android:strokeLineJoin="round"
|
||||||
android:strokeWidth="2"
|
android:strokeWidth="2"
|
||||||
android:fillColor="#00000000"
|
android:fillColor="#00000000"
|
||||||
android:strokeColor="#000000"
|
android:strokeColor="#000"
|
||||||
android:strokeLineCap="round"/>
|
android:strokeLineCap="round"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M52.741,30.464c0,0 0.953,8.551 -6.861,7.918c-2.62,-0.212 -7.816,-0.651 -7.867,-8.343c-0.005,-0.698 0.008,-1.599 0.811,-2.63c1.065,-1.367 3.572,-1.971 9.945,-1.422C48.769,25.988 52.215,25.889 52.741,30.464z"
|
android:pathData="M40.974,27.8716s1.309,-2.7346 2.6974,0"
|
||||||
android:strokeLineJoin="round"
|
android:strokeLineJoin="round"
|
||||||
android:strokeWidth="2"
|
android:strokeWidth="2"
|
||||||
android:fillColor="#00000000"
|
android:fillColor="#00000000"
|
||||||
android:strokeColor="#000000"
|
android:strokeColor="#000"
|
||||||
android:strokeLineCap="round"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M31.505,26.416c0,0 4.124,2.534 8.657,0"
|
|
||||||
android:strokeLineJoin="round"
|
|
||||||
android:strokeWidth="2"
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:strokeColor="#000000"
|
|
||||||
android:strokeLineCap="round"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M33.536,31.318c0,0 2.202,-3.751 4.536,0"
|
|
||||||
android:strokeLineJoin="round"
|
|
||||||
android:strokeWidth="2"
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:strokeColor="#000000"
|
|
||||||
android:strokeLineCap="round"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M52.664,29.933l0.433,-3.371l-3.833,-0.528"
|
|
||||||
android:strokeLineJoin="round"
|
|
||||||
android:strokeWidth="2"
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:strokeColor="#000000"
|
|
||||||
android:strokeLineCap="round"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M33.955,30.027c0,0 1.795,-3.751 3.699,0"
|
|
||||||
android:strokeLineJoin="round"
|
|
||||||
android:strokeWidth="2"
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:strokeColor="#000000"
|
|
||||||
android:strokeLineCap="round"/>
|
android:strokeLineCap="round"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
26
src/com.unprompted.tildefriends.yml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
id: com.unprompted.tildefriends
|
||||||
|
runtime: org.freedesktop.Platform
|
||||||
|
runtime-version: '23.08'
|
||||||
|
sdk: org.freedesktop.Sdk
|
||||||
|
command: tildefriends-run.sh
|
||||||
|
finish-args:
|
||||||
|
- --share=network
|
||||||
|
- --filesystem=xdg-data/applications/tildefriends
|
||||||
|
modules:
|
||||||
|
- name: tildefriends
|
||||||
|
buildsystem: simple
|
||||||
|
build-commands:
|
||||||
|
- make release out/data.zip
|
||||||
|
- install -Dm755 out/release/tildefriends /app/bin/tildefriends
|
||||||
|
- install -D out/data.zip /app/share/data.zip
|
||||||
|
- install -Dm755 tildefriends-run.sh /app/bin/tildefriends-run.sh
|
||||||
|
sources:
|
||||||
|
- type: git
|
||||||
|
url: https://dev.tildefriends.net/cory/tildefriends.git
|
||||||
|
dest: .
|
||||||
|
commit: main
|
||||||
|
- type: script
|
||||||
|
dest-filename: tildefriends-run.sh
|
||||||
|
commands:
|
||||||
|
- mkdir -p ~/.local/share/applications/tildefriends/
|
||||||
|
- exec tildefriends run -z /app/share/data.zip -d ~/.local/share/applications/tildefriends/db.sqlite
|
@ -390,8 +390,6 @@ static JSValue _database_remove(JSContext* context, JSValueConst this_val, int a
|
|||||||
typedef struct _database_get_all_t
|
typedef struct _database_get_all_t
|
||||||
{
|
{
|
||||||
const char* id;
|
const char* id;
|
||||||
const char* key;
|
|
||||||
size_t key_length;
|
|
||||||
char** out_values;
|
char** out_values;
|
||||||
size_t* out_lengths;
|
size_t* out_lengths;
|
||||||
int out_values_length;
|
int out_values_length;
|
||||||
@ -455,17 +453,11 @@ static JSValue _database_get_all(JSContext* context, JSValueConst this_val, int
|
|||||||
{
|
{
|
||||||
tf_ssb_t* ssb = tf_task_get_ssb(database->task);
|
tf_ssb_t* ssb = tf_task_get_ssb(database->task);
|
||||||
|
|
||||||
size_t length;
|
database_get_all_t* work = tf_malloc(sizeof(database_get_all_t) + strlen(database->id) + 1);
|
||||||
const char* key = JS_ToCStringLen(context, &length, argv[0]);
|
|
||||||
database_get_all_t* work = tf_malloc(sizeof(database_get_all_t) + strlen(database->id) + 1 + length + 1);
|
|
||||||
*work = (database_get_all_t) {
|
*work = (database_get_all_t) {
|
||||||
.id = (const char*)(work + 1),
|
.id = (const char*)(work + 1),
|
||||||
.key = (const char*)(work + 1) + strlen(database->id) + 1,
|
|
||||||
.key_length = length,
|
|
||||||
};
|
};
|
||||||
memcpy((char*)work->id, database->id, strlen(database->id) + 1);
|
memcpy((char*)work->id, database->id, strlen(database->id) + 1);
|
||||||
memcpy((char*)work->key, key, length + 1);
|
|
||||||
JS_FreeCString(context, key);
|
|
||||||
|
|
||||||
tf_ssb_run_work(ssb, _database_get_all_work, _database_get_all_after_work, work);
|
tf_ssb_run_work(ssb, _database_get_all_work, _database_get_all_after_work, work);
|
||||||
result = JS_NewPromiseCapability(context, work->promise);
|
result = JS_NewPromiseCapability(context, work->promise);
|
||||||
|
53
src/http.c
@ -67,7 +67,6 @@ typedef struct _tf_http_connection_t
|
|||||||
typedef struct _tf_http_handler_t
|
typedef struct _tf_http_handler_t
|
||||||
{
|
{
|
||||||
const char* pattern;
|
const char* pattern;
|
||||||
bool is_wildcard;
|
|
||||||
tf_http_callback_t* callback;
|
tf_http_callback_t* callback;
|
||||||
tf_http_cleanup_t* cleanup;
|
tf_http_cleanup_t* cleanup;
|
||||||
void* user_data;
|
void* user_data;
|
||||||
@ -107,6 +106,7 @@ static const char* _http_connection_get_header(const tf_http_connection_t* conne
|
|||||||
static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason);
|
static void _http_connection_destroy(tf_http_connection_t* connection, const char* reason);
|
||||||
static void _http_timer_reset(tf_http_connection_t* connection);
|
static void _http_timer_reset(tf_http_connection_t* connection);
|
||||||
static void _http_tls_update(tf_http_connection_t* connection);
|
static void _http_tls_update(tf_http_connection_t* connection);
|
||||||
|
static void _http_builtin_404_handler(tf_http_request_t* request);
|
||||||
|
|
||||||
tf_http_t* tf_http_create(uv_loop_t* loop)
|
tf_http_t* tf_http_create(uv_loop_t* loop)
|
||||||
{
|
{
|
||||||
@ -128,9 +128,15 @@ static void _http_allocate_buffer(uv_handle_t* handle, size_t suggested_size, uv
|
|||||||
*buf = uv_buf_init(connection->incoming, sizeof(connection->incoming));
|
*buf = uv_buf_init(connection->incoming, sizeof(connection->incoming));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _http_pattern_matches(const char* pattern, const char* path, bool is_wildcard)
|
bool tf_http_pattern_matches(const char* pattern, const char* path)
|
||||||
{
|
{
|
||||||
if (!pattern || !*pattern || (!is_wildcard && strcmp(path, pattern) == 0))
|
if (!*pattern && !*path)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const char* k_word = "{word}";
|
||||||
|
bool is_wildcard = strchr(pattern, '*') || strstr(pattern, k_word);
|
||||||
|
if (!is_wildcard && strcmp(path, pattern) == 0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -139,17 +145,36 @@ static bool _http_pattern_matches(const char* pattern, const char* path, bool is
|
|||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
while (pattern[i] && path[j] && pattern[i] != '*' && pattern[i] == path[j])
|
while (pattern[i] && path[j] && pattern[i] == path[j])
|
||||||
{
|
{
|
||||||
i++;
|
i++;
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pattern[i] == '*')
|
size_t k_word_len = strlen(k_word);
|
||||||
|
if (strncmp(pattern + i, k_word, k_word_len) == 0 && ((path[j] >= 'a' && path[j] <= 'z') || (path[j] >= 'A' && path[j] <= 'Z')))
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (_http_pattern_matches(pattern + i + 1, path + j, strchr(pattern + i + 1, '*') != NULL))
|
if ((path[j] >= 'a' && path[j] <= 'z') || (path[j] >= 'A' && path[j] <= 'Z') || (path[j] >= '0' && path[j] <= '9'))
|
||||||
|
{
|
||||||
|
if (tf_http_pattern_matches(pattern + i + k_word_len, path + j + 1))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pattern[i] == '*')
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (tf_http_pattern_matches(pattern + i + 1, path + j))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -169,7 +194,7 @@ static bool _http_find_handler(tf_http_t* http, const char* path, tf_http_callba
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < http->handlers_count; i++)
|
for (int i = 0; i < http->handlers_count; i++)
|
||||||
{
|
{
|
||||||
if (_http_pattern_matches(http->handlers[i].pattern, path, http->handlers[i].is_wildcard))
|
if (tf_http_pattern_matches(http->handlers[i].pattern, path))
|
||||||
{
|
{
|
||||||
*out_callback = http->handlers[i].callback;
|
*out_callback = http->handlers[i].callback;
|
||||||
*out_trace_name = http->handlers[i].pattern;
|
*out_trace_name = http->handlers[i].pattern;
|
||||||
@ -196,6 +221,10 @@ static void _http_connection_on_close(uv_handle_t* handle)
|
|||||||
static void _http_request_destroy(tf_http_request_t* request)
|
static void _http_request_destroy(tf_http_request_t* request)
|
||||||
{
|
{
|
||||||
tf_http_close_callback* on_close = request->on_close;
|
tf_http_close_callback* on_close = request->on_close;
|
||||||
|
if (request->connection && !request->connection->is_response_sent)
|
||||||
|
{
|
||||||
|
_http_builtin_404_handler(request);
|
||||||
|
}
|
||||||
if (on_close)
|
if (on_close)
|
||||||
{
|
{
|
||||||
tf_trace_t* trace = request->http->trace;
|
tf_trace_t* trace = request->http->trace;
|
||||||
@ -402,6 +431,11 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
|
|||||||
|
|
||||||
if (connection->body_length == connection->content_length)
|
if (connection->body_length == connection->content_length)
|
||||||
{
|
{
|
||||||
|
/* Null-terminate for convenience. */
|
||||||
|
if (connection->body)
|
||||||
|
{
|
||||||
|
((char*)connection->body)[connection->body_length] = '\0';
|
||||||
|
}
|
||||||
tf_http_request_t* request = tf_malloc(sizeof(tf_http_request_t));
|
tf_http_request_t* request = tf_malloc(sizeof(tf_http_request_t));
|
||||||
*request = (tf_http_request_t) {
|
*request = (tf_http_request_t) {
|
||||||
.http = connection->http,
|
.http = connection->http,
|
||||||
@ -495,7 +529,7 @@ static size_t _http_on_read_plain_internal(tf_http_connection_t* connection, con
|
|||||||
|
|
||||||
if (connection->content_length)
|
if (connection->content_length)
|
||||||
{
|
{
|
||||||
connection->body = tf_realloc(connection->body, connection->content_length);
|
connection->body = tf_realloc(connection->body, connection->content_length + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_http_find_handler(connection->http, connection->path, &connection->callback, &connection->trace_name, &connection->user_data) || !connection->callback)
|
if (!_http_find_handler(connection->http, connection->path, &connection->callback, &connection->trace_name, &connection->user_data) || !connection->callback)
|
||||||
@ -731,7 +765,6 @@ void tf_http_add_handler(tf_http_t* http, const char* pattern, tf_http_callback_
|
|||||||
http->handlers = tf_resize_vec(http->handlers, sizeof(tf_http_handler_t) * (http->handlers_count + 1));
|
http->handlers = tf_resize_vec(http->handlers, sizeof(tf_http_handler_t) * (http->handlers_count + 1));
|
||||||
http->handlers[http->handlers_count++] = (tf_http_handler_t) {
|
http->handlers[http->handlers_count++] = (tf_http_handler_t) {
|
||||||
.pattern = tf_strdup(pattern),
|
.pattern = tf_strdup(pattern),
|
||||||
.is_wildcard = pattern && strchr(pattern, '*') != NULL,
|
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.cleanup = cleanup,
|
.cleanup = cleanup,
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
@ -1071,7 +1104,7 @@ void* tf_http_get_user_data(tf_http_t* http)
|
|||||||
|
|
||||||
const char* tf_http_get_cookie(const char* cookie_header, const char* name)
|
const char* tf_http_get_cookie(const char* cookie_header, const char* name)
|
||||||
{
|
{
|
||||||
if (!cookie_header)
|
if (!cookie_header || !name)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -228,4 +228,12 @@ void tf_http_request_websocket_upgrade(tf_http_request_t* request);
|
|||||||
*/
|
*/
|
||||||
const char* tf_http_status_text(int status);
|
const char* tf_http_status_text(int status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Match URL patterns. "*" matches anything, and "{word}" matches [a-zA-Z][a-zA-Z0-9]*".
|
||||||
|
** @param pattern The pattern to match.
|
||||||
|
** @param path The path to test.
|
||||||
|
** @return true if the path matches the pattern.
|
||||||
|
*/
|
||||||
|
bool tf_http_pattern_matches(const char* pattern, const char* path);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
731
src/httpd.js.c
@ -4,12 +4,13 @@
|
|||||||
#include "http.h"
|
#include "http.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "ssb.h"
|
|
||||||
#include "ssb.db.h"
|
#include "ssb.db.h"
|
||||||
|
#include "ssb.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
#include "tlscontext.js.h"
|
#include "tlscontext.js.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "util.js.h"
|
#include "util.js.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
#include "ow-crypt.h"
|
#include "ow-crypt.h"
|
||||||
|
|
||||||
@ -33,14 +34,18 @@
|
|||||||
|
|
||||||
#define CYAN "\e[1;36m"
|
#define CYAN "\e[1;36m"
|
||||||
#define MAGENTA "\e[1;35m"
|
#define MAGENTA "\e[1;35m"
|
||||||
|
#define YELLOW "\e[1;33m"
|
||||||
#define RESET "\e[0m"
|
#define RESET "\e[0m"
|
||||||
|
|
||||||
const int64_t k_refresh_interval = 1ULL * 7 * 24 * 60 * 60 * 1000;
|
const int64_t k_refresh_interval = 1ULL * 7 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
static JSValue _authenticate_jwt(tf_ssb_t* ssb, JSContext* context, const char* jwt);
|
static JSValue _authenticate_jwt(tf_ssb_t* ssb, JSContext* context, const char* jwt);
|
||||||
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(tf_ssb_t* ssb, const char* name);
|
static bool _is_name_valid(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;
|
||||||
@ -219,6 +224,17 @@ static void _httpd_message_callback(tf_http_request_t* request, int op_code, con
|
|||||||
JS_FreeValue(context, on_message);
|
JS_FreeValue(context, on_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSValue _httpd_make_response_object(JSContext* context, tf_http_request_t* request)
|
||||||
|
{
|
||||||
|
JSValue response_object = JS_NewObjectClass(context, _httpd_request_class_id);
|
||||||
|
JS_SetOpaque(response_object, request);
|
||||||
|
JS_SetPropertyStr(context, response_object, "writeHead", JS_NewCFunction(context, _httpd_response_write_head, "writeHead", 2));
|
||||||
|
JS_SetPropertyStr(context, response_object, "end", JS_NewCFunction(context, _httpd_response_end, "end", 1));
|
||||||
|
JS_SetPropertyStr(context, response_object, "send", JS_NewCFunction(context, _httpd_response_send, "send", 2));
|
||||||
|
JS_SetPropertyStr(context, response_object, "upgrade", JS_NewCFunction(context, _httpd_websocket_upgrade, "upgrade", 2));
|
||||||
|
return response_object;
|
||||||
|
}
|
||||||
|
|
||||||
static void _httpd_callback_internal(tf_http_request_t* request, bool is_websocket)
|
static void _httpd_callback_internal(tf_http_request_t* request, bool is_websocket)
|
||||||
{
|
{
|
||||||
http_handler_data_t* data = request->user_data;
|
http_handler_data_t* data = request->user_data;
|
||||||
@ -245,14 +261,9 @@ static void _httpd_callback_internal(tf_http_request_t* request, bool is_websock
|
|||||||
JS_SetPropertyStr(context, client, "tls", request->is_tls ? JS_TRUE : JS_FALSE);
|
JS_SetPropertyStr(context, client, "tls", request->is_tls ? JS_TRUE : JS_FALSE);
|
||||||
JS_SetPropertyStr(context, request_object, "client", client);
|
JS_SetPropertyStr(context, request_object, "client", client);
|
||||||
|
|
||||||
JSValue response_object = JS_NewObjectClass(context, _httpd_request_class_id);
|
JSValue response_object = _httpd_make_response_object(context, request);
|
||||||
/* The ref is owned by the JS object and will be released by the finalizer. */
|
/* The ref is owned by the JS object and will be released by the finalizer. */
|
||||||
tf_http_request_ref(request);
|
tf_http_request_ref(request);
|
||||||
JS_SetOpaque(response_object, request);
|
|
||||||
JS_SetPropertyStr(context, response_object, "writeHead", JS_NewCFunction(context, _httpd_response_write_head, "writeHead", 2));
|
|
||||||
JS_SetPropertyStr(context, response_object, "end", JS_NewCFunction(context, _httpd_response_end, "end", 1));
|
|
||||||
JS_SetPropertyStr(context, response_object, "send", JS_NewCFunction(context, _httpd_response_send, "send", 2));
|
|
||||||
JS_SetPropertyStr(context, response_object, "upgrade", JS_NewCFunction(context, _httpd_websocket_upgrade, "upgrade", 2));
|
|
||||||
JSValue args[] = {
|
JSValue args[] = {
|
||||||
request_object,
|
request_object,
|
||||||
response_object,
|
response_object,
|
||||||
@ -334,7 +345,7 @@ static JSValue _httpd_websocket_upgrade(JSContext* context, JSValueConst this_va
|
|||||||
tf_free((void*)session);
|
tf_free((void*)session);
|
||||||
JSValue name = !JS_IsUndefined(jwt) ? JS_GetPropertyStr(context, jwt, "name") : JS_UNDEFINED;
|
JSValue name = !JS_IsUndefined(jwt) ? JS_GetPropertyStr(context, jwt, "name") : JS_UNDEFINED;
|
||||||
const char* name_string = !JS_IsUndefined(name) ? JS_ToCString(context, name) : NULL;
|
const char* name_string = !JS_IsUndefined(name) ? JS_ToCString(context, name) : NULL;
|
||||||
const char* session_token = _make_session_jwt(ssb, name_string);
|
const char* session_token = _make_session_jwt(tf_ssb_get_context(ssb), ssb, name_string);
|
||||||
const char* cookie = _make_set_session_cookie_header(request, session_token);
|
const char* cookie = _make_set_session_cookie_header(request, session_token);
|
||||||
tf_free((void*)session_token);
|
tf_free((void*)session_token);
|
||||||
JS_FreeCString(context, name_string);
|
JS_FreeCString(context, name_string);
|
||||||
@ -420,7 +431,7 @@ static JSValue _httpd_endpoint_start(JSContext* context, JSValueConst this_val,
|
|||||||
*listener = (httpd_listener_t) { .context = context, .tls = JS_DupValue(context, argv[1]) };
|
*listener = (httpd_listener_t) { .context = context, .tls = JS_DupValue(context, argv[1]) };
|
||||||
tf_tls_context_t* tls = tf_tls_context_get(listener->tls);
|
tf_tls_context_t* tls = tf_tls_context_get(listener->tls);
|
||||||
int assigned_port = tf_http_listen(http, port, tls, _httpd_listener_cleanup, listener);
|
int assigned_port = tf_http_listen(http, port, tls, _httpd_listener_cleanup, listener);
|
||||||
tf_printf(CYAN "~😎 Tilde Friends" RESET " is now up at " MAGENTA "http%s://127.0.0.1:%d/" RESET ".\n", tls ? "s" : "", assigned_port);
|
tf_printf(CYAN "~😎 Tilde Friends" RESET " " YELLOW VERSION_NUMBER RESET " is now up at " MAGENTA "http%s://127.0.0.1:%d/" RESET ".\n", tls ? "s" : "", assigned_port);
|
||||||
return JS_NewInt32(context, assigned_port);
|
return JS_NewInt32(context, assigned_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,14 +566,11 @@ static bool _magic_bytes_match(const magic_bytes_t* magic, const uint8_t* actual
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue _httpd_mime_type_from_magic_bytes(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static const char* _httpd_mime_type_from_magic_bytes(const uint8_t* bytes, size_t size)
|
||||||
{
|
{
|
||||||
JSValue result = JS_UNDEFINED;
|
const char* type = "application/binary";
|
||||||
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",
|
||||||
@ -627,12 +635,12 @@ static JSValue _httpd_mime_type_from_magic_bytes(JSContext* context, JSValueCons
|
|||||||
{
|
{
|
||||||
if (_magic_bytes_match(&k_magic_bytes[i], bytes, size))
|
if (_magic_bytes_match(&k_magic_bytes[i], bytes, size))
|
||||||
{
|
{
|
||||||
result = JS_NewString(context, k_magic_bytes[i].type);
|
type = k_magic_bytes[i].type;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@ -667,14 +675,6 @@ static const char* _ext_to_content_type(const char* ext, bool use_fallback)
|
|||||||
return use_fallback ? "application/binary" : NULL;
|
return use_fallback ? "application/binary" : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue _httpd_mime_type_from_extension(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
|
||||||
{
|
|
||||||
const char* name = JS_ToCString(context, argv[0]);
|
|
||||||
const char* type = _ext_to_content_type(strrchr(name, '.'), false);
|
|
||||||
JS_FreeCString(context, name);
|
|
||||||
return type ? JS_NewString(context, type) : JS_UNDEFINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _httpd_finalizer(JSRuntime* runtime, JSValue value)
|
static void _httpd_finalizer(JSRuntime* runtime, JSValue value)
|
||||||
{
|
{
|
||||||
tf_http_t* http = JS_GetOpaque(value, _httpd_class_id);
|
tf_http_t* http = JS_GetOpaque(value, _httpd_class_id);
|
||||||
@ -905,14 +905,23 @@ static void _httpd_endpoint_static(tf_http_request_t* request)
|
|||||||
const char* file_path = NULL;
|
const char* file_path = NULL;
|
||||||
for (int i = 0; i < tf_countof(k_map) && !after; i++)
|
for (int i = 0; i < tf_countof(k_map) && !after; i++)
|
||||||
{
|
{
|
||||||
after = _after(request->path, k_map[i][0]);
|
const char* next_after = _after(request->path, k_map[i][0]);
|
||||||
|
if (next_after)
|
||||||
|
{
|
||||||
|
after = next_after;
|
||||||
file_path = k_map[i][1];
|
file_path = k_map[i][1];
|
||||||
is_core = is_core || (after && i == 0);
|
is_core = after && i == 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(request->path, "/speedscope/") == 0)
|
if ((!after || !*after) && request->path[strlen(request->path) - 1] == '/')
|
||||||
{
|
{
|
||||||
after = "index.html";
|
after = "index.html";
|
||||||
|
if (!file_path)
|
||||||
|
{
|
||||||
|
file_path = "core/";
|
||||||
|
is_core = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!after || strstr(after, ".."))
|
if (!after || strstr(after, ".."))
|
||||||
@ -950,6 +959,621 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _httpd_endpoint_add_slash(tf_http_request_t* request)
|
||||||
|
{
|
||||||
|
const char* host = tf_http_request_get_header(request, "x-forwarded-host");
|
||||||
|
if (!host)
|
||||||
|
{
|
||||||
|
host = tf_http_request_get_header(request, "host");
|
||||||
|
}
|
||||||
|
char url[1024];
|
||||||
|
snprintf(url, sizeof(url), "%s%s%s/", request->is_tls ? "https://" : "http://", host, request->path);
|
||||||
|
const char* headers[] = {
|
||||||
|
"Location",
|
||||||
|
url,
|
||||||
|
};
|
||||||
|
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, "", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _user_app_t
|
||||||
|
{
|
||||||
|
const char* user;
|
||||||
|
const char* app;
|
||||||
|
} user_app_t;
|
||||||
|
|
||||||
|
static user_app_t* _parse_user_app_from_path(const char* path, const char* expected_suffix)
|
||||||
|
{
|
||||||
|
if (!path || path[0] != '/' || path[1] != '~')
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = strlen(path);
|
||||||
|
size_t suffix_length = expected_suffix ? strlen(expected_suffix) : 0;
|
||||||
|
if (length < suffix_length || strcmp(path + length - suffix_length, expected_suffix) != 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* slash = strchr(path + 2, '/');
|
||||||
|
if (!slash)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* user = path + 2;
|
||||||
|
size_t user_length = (size_t)(slash - user);
|
||||||
|
const char* app = slash + 1;
|
||||||
|
size_t app_length = (size_t)(length - suffix_length - user_length - 3);
|
||||||
|
user_app_t* result = tf_malloc(sizeof(user_app_t) + user_length + 1 + app_length + 1);
|
||||||
|
|
||||||
|
*result = (user_app_t) {
|
||||||
|
.user = (char*)(result + 1),
|
||||||
|
.app = (char*)(result + 1) + user_length + 1,
|
||||||
|
};
|
||||||
|
memcpy((char*)result->user, user, user_length);
|
||||||
|
((char*)result->user)[user_length] = '\0';
|
||||||
|
memcpy((char*)result->app, app, app_length);
|
||||||
|
((char*)result->app)[app_length] = '\0';
|
||||||
|
|
||||||
|
if (!_is_name_valid(result->user) || !_is_name_valid(result->app))
|
||||||
|
{
|
||||||
|
tf_free(result);
|
||||||
|
result = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _app_blob_t
|
||||||
|
{
|
||||||
|
tf_http_request_t* request;
|
||||||
|
bool found;
|
||||||
|
bool not_modified;
|
||||||
|
bool use_handler;
|
||||||
|
void* data;
|
||||||
|
size_t size;
|
||||||
|
char app_blob_id[k_blob_id_len];
|
||||||
|
const char* file;
|
||||||
|
user_app_t* user_app;
|
||||||
|
char etag[256];
|
||||||
|
} app_blob_t;
|
||||||
|
|
||||||
|
static void _httpd_endpoint_app_blob_work(tf_ssb_t* ssb, void* user_data)
|
||||||
|
{
|
||||||
|
app_blob_t* data = user_data;
|
||||||
|
tf_http_request_t* request = data->request;
|
||||||
|
if (request->path[0] == '/' && request->path[1] == '~')
|
||||||
|
{
|
||||||
|
const char* last_slash = strchr(request->path + 1, '/');
|
||||||
|
if (last_slash)
|
||||||
|
{
|
||||||
|
last_slash = strchr(last_slash + 1, '/');
|
||||||
|
}
|
||||||
|
data->user_app = last_slash ? _parse_user_app_from_path(request->path, last_slash) : NULL;
|
||||||
|
if (data->user_app)
|
||||||
|
{
|
||||||
|
size_t path_length = strlen("path:") + strlen(data->user_app->app) + 1;
|
||||||
|
char* app_path = tf_malloc(path_length);
|
||||||
|
snprintf(app_path, path_length, "path:%s", data->user_app->app);
|
||||||
|
const char* value = tf_ssb_db_get_property(ssb, data->user_app->user, app_path);
|
||||||
|
snprintf(data->app_blob_id, sizeof(data->app_blob_id), "%s", value);
|
||||||
|
tf_free(app_path);
|
||||||
|
tf_free((void*)value);
|
||||||
|
data->file = last_slash + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (request->path[0] == '/' && request->path[1] == '&')
|
||||||
|
{
|
||||||
|
const char* end = strstr(request->path, ".sha256/");
|
||||||
|
if (end)
|
||||||
|
{
|
||||||
|
snprintf(data->app_blob_id, sizeof(data->app_blob_id), "%.*s", (int)(end + strlen(".sha256") - request->path - 1), request->path + 1);
|
||||||
|
data->file = end + strlen(".sha256/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* app_blob = NULL;
|
||||||
|
size_t app_blob_size = 0;
|
||||||
|
if (*data->app_blob_id && tf_ssb_db_blob_get(ssb, data->app_blob_id, (uint8_t**)&app_blob, &app_blob_size))
|
||||||
|
{
|
||||||
|
JSMallocFunctions funcs = { 0 };
|
||||||
|
tf_get_js_malloc_functions(&funcs);
|
||||||
|
JSRuntime* runtime = JS_NewRuntime2(&funcs, NULL);
|
||||||
|
JSContext* context = JS_NewContext(runtime);
|
||||||
|
|
||||||
|
JSValue app_object = JS_ParseJSON(context, app_blob, app_blob_size, NULL);
|
||||||
|
JSValue files = JS_GetPropertyStr(context, app_object, "files");
|
||||||
|
JSValue blob_id = JS_GetPropertyStr(context, files, data->file);
|
||||||
|
if (JS_IsUndefined(blob_id))
|
||||||
|
{
|
||||||
|
blob_id = JS_GetPropertyStr(context, files, "handler.js");
|
||||||
|
if (!JS_IsUndefined(blob_id))
|
||||||
|
{
|
||||||
|
data->use_handler = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char* blob_id_str = JS_ToCString(context, blob_id);
|
||||||
|
if (blob_id_str)
|
||||||
|
{
|
||||||
|
snprintf(data->etag, sizeof(data->etag), "\"%s\"", blob_id_str);
|
||||||
|
const char* match = tf_http_request_get_header(data->request, "if-none-match");
|
||||||
|
if (match && strcmp(match, data->etag) == 0)
|
||||||
|
{
|
||||||
|
data->not_modified = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data->found = tf_ssb_db_blob_get(ssb, blob_id_str, (uint8_t**)&data->data, &data->size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JS_FreeCString(context, blob_id_str);
|
||||||
|
}
|
||||||
|
JS_FreeValue(context, blob_id);
|
||||||
|
JS_FreeValue(context, files);
|
||||||
|
JS_FreeValue(context, app_object);
|
||||||
|
|
||||||
|
JS_FreeContext(context);
|
||||||
|
JS_FreeRuntime(runtime);
|
||||||
|
tf_free(app_blob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _httpd_call_app_handler(tf_ssb_t* ssb, tf_http_request_t* request, const char* app_blob_id, const char* path, const char* package_owner, const char* app)
|
||||||
|
{
|
||||||
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
|
JSValue global = JS_GetGlobalObject(context);
|
||||||
|
JSValue exports = JS_GetPropertyStr(context, global, "exports");
|
||||||
|
JSValue call_app_handler = JS_GetPropertyStr(context, exports, "callAppHandler");
|
||||||
|
|
||||||
|
JSValue response = _httpd_make_response_object(context, request);
|
||||||
|
tf_http_request_ref(request);
|
||||||
|
JSValue handler_blob_id = JS_NewString(context, app_blob_id);
|
||||||
|
JSValue path_value = JS_NewString(context, path);
|
||||||
|
JSValue package_owner_value = JS_NewString(context, package_owner);
|
||||||
|
JSValue app_value = JS_NewString(context, app);
|
||||||
|
JSValue query_value = request->query ? JS_NewString(context, request->query) : JS_UNDEFINED;
|
||||||
|
|
||||||
|
JSValue headers = JS_NewObject(context);
|
||||||
|
for (int i = 0; i < request->headers_count; i++)
|
||||||
|
{
|
||||||
|
char name[256] = "";
|
||||||
|
snprintf(name, sizeof(name), "%.*s", (int)request->headers[i].name_len, request->headers[i].name);
|
||||||
|
JS_SetPropertyStr(context, headers, name, JS_NewStringLen(context, request->headers[i].value, request->headers[i].value_len));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue args[] = {
|
||||||
|
response,
|
||||||
|
handler_blob_id,
|
||||||
|
path_value,
|
||||||
|
query_value,
|
||||||
|
headers,
|
||||||
|
package_owner_value,
|
||||||
|
app_value,
|
||||||
|
};
|
||||||
|
|
||||||
|
JSValue result = JS_Call(context, call_app_handler, JS_NULL, tf_countof(args), args);
|
||||||
|
tf_util_report_error(context, result);
|
||||||
|
JS_FreeValue(context, result);
|
||||||
|
|
||||||
|
JS_FreeValue(context, headers);
|
||||||
|
JS_FreeValue(context, query_value);
|
||||||
|
JS_FreeValue(context, app_value);
|
||||||
|
JS_FreeValue(context, package_owner_value);
|
||||||
|
JS_FreeValue(context, handler_blob_id);
|
||||||
|
JS_FreeValue(context, path_value);
|
||||||
|
JS_FreeValue(context, response);
|
||||||
|
JS_FreeValue(context, call_app_handler);
|
||||||
|
JS_FreeValue(context, exports);
|
||||||
|
JS_FreeValue(context, global);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _httpd_endpoint_app_blob_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||||
|
{
|
||||||
|
app_blob_t* data = user_data;
|
||||||
|
if (data->not_modified)
|
||||||
|
{
|
||||||
|
tf_http_respond(data->request, 304, NULL, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
else if (data->use_handler)
|
||||||
|
{
|
||||||
|
_httpd_call_app_handler(ssb, data->request, data->app_blob_id, data->file, data->user_app->user, data->user_app->app);
|
||||||
|
}
|
||||||
|
else if (data->found)
|
||||||
|
{
|
||||||
|
const char* mime_type = _ext_to_content_type(strrchr(data->request->path, '.'), false);
|
||||||
|
if (!mime_type)
|
||||||
|
{
|
||||||
|
mime_type = _httpd_mime_type_from_magic_bytes(data->data, data->size);
|
||||||
|
}
|
||||||
|
const char* headers[] = {
|
||||||
|
"Access-Control-Allow-Origin",
|
||||||
|
"*",
|
||||||
|
"Content-Security-Policy",
|
||||||
|
"sandbox allow-downloads allow-top-navigation-by-user-activation",
|
||||||
|
"Content-Type",
|
||||||
|
mime_type ? mime_type : "application/binary",
|
||||||
|
"etag",
|
||||||
|
data->etag,
|
||||||
|
};
|
||||||
|
tf_http_respond(data->request, 200, headers, tf_countof(headers) / 2, data->data, data->size);
|
||||||
|
}
|
||||||
|
tf_free(data->user_app);
|
||||||
|
tf_free(data->data);
|
||||||
|
tf_http_request_unref(data->request);
|
||||||
|
tf_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _httpd_endpoint_app_blob(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);
|
||||||
|
app_blob_t* data = tf_malloc(sizeof(app_blob_t));
|
||||||
|
*data = (app_blob_t) { .request = request };
|
||||||
|
tf_ssb_run_work(ssb, _httpd_endpoint_app_blob_work, _httpd_endpoint_app_blob_after_work, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _view_t
|
||||||
|
{
|
||||||
|
tf_http_request_t* request;
|
||||||
|
const char** form_data;
|
||||||
|
void* data;
|
||||||
|
size_t size;
|
||||||
|
char etag[256];
|
||||||
|
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[128] = "";
|
||||||
|
|
||||||
|
user_app_t* user_app = _parse_user_app_from_path(request->path, "/view");
|
||||||
|
if (user_app)
|
||||||
|
{
|
||||||
|
size_t app_path_length = strlen("path:") + strlen(user_app->app) + 1;
|
||||||
|
char* app_path = tf_malloc(app_path_length);
|
||||||
|
snprintf(app_path, app_path_length, "path:%s", user_app->app);
|
||||||
|
const char* value = tf_ssb_db_get_property(ssb, user_app->user, app_path);
|
||||||
|
snprintf(blob_id, sizeof(blob_id), "%s", value);
|
||||||
|
tf_free(app_path);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
tf_free(user_app);
|
||||||
|
|
||||||
|
if (*blob_id)
|
||||||
|
{
|
||||||
|
snprintf(view->etag, sizeof(view->etag), "\"%s\"", 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) == 0)
|
||||||
|
{
|
||||||
|
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(view->data, view->size) : "text/plain",
|
||||||
|
"etag",
|
||||||
|
view->etag,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _save_t
|
||||||
|
{
|
||||||
|
tf_http_request_t* request;
|
||||||
|
int response;
|
||||||
|
char blob_id[256];
|
||||||
|
} save_t;
|
||||||
|
|
||||||
|
static void _httpd_endpoint_save_work(tf_ssb_t* ssb, void* user_data)
|
||||||
|
{
|
||||||
|
save_t* save = user_data;
|
||||||
|
tf_http_request_t* request = save->request;
|
||||||
|
const char* session = tf_http_get_cookie(tf_http_request_get_header(request, "cookie"), "session");
|
||||||
|
|
||||||
|
JSMallocFunctions funcs = { 0 };
|
||||||
|
tf_get_js_malloc_functions(&funcs);
|
||||||
|
JSRuntime* runtime = JS_NewRuntime2(&funcs, NULL);
|
||||||
|
JSContext* context = JS_NewContext(runtime);
|
||||||
|
|
||||||
|
JSValue jwt = _authenticate_jwt(ssb, context, session);
|
||||||
|
JSValue user = JS_GetPropertyStr(context, jwt, "name");
|
||||||
|
const char* user_string = JS_ToCString(context, user);
|
||||||
|
|
||||||
|
if (user_string && _is_name_valid(user_string))
|
||||||
|
{
|
||||||
|
user_app_t* user_app = _parse_user_app_from_path(request->path, "/save");
|
||||||
|
if (user_app)
|
||||||
|
{
|
||||||
|
if (strcmp(user_string, user_app->user) == 0 || (strcmp(user_app->user, "core") == 0 && tf_ssb_db_user_has_permission(ssb, user_string, "administration")))
|
||||||
|
{
|
||||||
|
size_t path_length = strlen("path:") + strlen(user_app->app) + 1;
|
||||||
|
char* app_path = tf_malloc(path_length);
|
||||||
|
snprintf(app_path, path_length, "path:%s", user_app->app);
|
||||||
|
|
||||||
|
const char* old_blob_id = tf_ssb_db_get_property(ssb, user_app->user, app_path);
|
||||||
|
|
||||||
|
JSValue new_app = JS_ParseJSON(context, request->body, request->content_length, NULL);
|
||||||
|
tf_util_report_error(context, new_app);
|
||||||
|
if (JS_IsObject(new_app))
|
||||||
|
{
|
||||||
|
uint8_t* old_blob = NULL;
|
||||||
|
size_t old_blob_size = 0;
|
||||||
|
if (tf_ssb_db_blob_get(ssb, old_blob_id, &old_blob, &old_blob_size))
|
||||||
|
{
|
||||||
|
JSValue old_app = JS_ParseJSON(context, (const char*)old_blob, old_blob_size, NULL);
|
||||||
|
if (JS_IsObject(old_app))
|
||||||
|
{
|
||||||
|
JSAtom previous = JS_NewAtom(context, "previous");
|
||||||
|
JS_DeleteProperty(context, old_app, previous, 0);
|
||||||
|
JS_DeleteProperty(context, new_app, previous, 0);
|
||||||
|
|
||||||
|
JSValue old_app_json = JS_JSONStringify(context, old_app, JS_NULL, JS_NULL);
|
||||||
|
JSValue new_app_json = JS_JSONStringify(context, new_app, JS_NULL, JS_NULL);
|
||||||
|
const char* old_app_str = JS_ToCString(context, old_app_json);
|
||||||
|
const char* new_app_str = JS_ToCString(context, new_app_json);
|
||||||
|
|
||||||
|
if (old_app_str && new_app_str && strcmp(old_app_str, new_app_str) == 0)
|
||||||
|
{
|
||||||
|
snprintf(save->blob_id, sizeof(save->blob_id), "/%s", old_blob_id);
|
||||||
|
save->response = 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FreeCString(context, old_app_str);
|
||||||
|
JS_FreeCString(context, new_app_str);
|
||||||
|
JS_FreeValue(context, old_app_json);
|
||||||
|
JS_FreeValue(context, new_app_json);
|
||||||
|
JS_FreeAtom(context, previous);
|
||||||
|
}
|
||||||
|
JS_FreeValue(context, old_app);
|
||||||
|
tf_free(old_blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!save->response)
|
||||||
|
{
|
||||||
|
if (old_blob_id)
|
||||||
|
{
|
||||||
|
JS_SetPropertyStr(context, new_app, "previous", JS_NewString(context, old_blob_id));
|
||||||
|
}
|
||||||
|
JSValue new_app_json = JS_JSONStringify(context, new_app, JS_NULL, JS_NULL);
|
||||||
|
size_t new_app_length = 0;
|
||||||
|
const char* new_app_str = JS_ToCStringLen(context, &new_app_length, new_app_json);
|
||||||
|
|
||||||
|
char blob_id[250] = { 0 };
|
||||||
|
if (tf_ssb_db_blob_store(ssb, (const uint8_t*)new_app_str, new_app_length, blob_id, sizeof(blob_id), NULL) &&
|
||||||
|
tf_ssb_db_set_property(ssb, user_app->user, app_path, blob_id))
|
||||||
|
{
|
||||||
|
tf_ssb_db_add_value_to_array_property(ssb, user_app->user, "apps", user_app->app);
|
||||||
|
snprintf(save->blob_id, sizeof(save->blob_id), "/%s", blob_id);
|
||||||
|
save->response = 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FreeCString(context, new_app_str);
|
||||||
|
JS_FreeValue(context, new_app_json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
save->response = 400;
|
||||||
|
}
|
||||||
|
JS_FreeValue(context, new_app);
|
||||||
|
|
||||||
|
tf_free(app_path);
|
||||||
|
tf_free((void*)old_blob_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
save->response = 401;
|
||||||
|
}
|
||||||
|
tf_free(user_app);
|
||||||
|
}
|
||||||
|
else if (strcmp(request->path, "/save") == 0)
|
||||||
|
{
|
||||||
|
char blob_id[250] = { 0 };
|
||||||
|
if (tf_ssb_db_blob_store(ssb, request->body, request->content_length, blob_id, sizeof(blob_id), NULL))
|
||||||
|
{
|
||||||
|
snprintf(save->blob_id, sizeof(save->blob_id), "/%s", blob_id);
|
||||||
|
save->response = 200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
save->response = 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tf_free((void*)session);
|
||||||
|
JS_FreeCString(context, user_string);
|
||||||
|
JS_FreeValue(context, user);
|
||||||
|
JS_FreeValue(context, jwt);
|
||||||
|
JS_FreeContext(context);
|
||||||
|
JS_FreeRuntime(runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _httpd_endpoint_save_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||||
|
{
|
||||||
|
save_t* save = user_data;
|
||||||
|
tf_http_request_t* request = save->request;
|
||||||
|
if (*save->blob_id)
|
||||||
|
{
|
||||||
|
tf_http_respond(request, 200, NULL, 0, save->blob_id, strlen(save->blob_id));
|
||||||
|
}
|
||||||
|
tf_http_request_unref(request);
|
||||||
|
tf_free(save);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _httpd_endpoint_save(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);
|
||||||
|
save_t* save = tf_malloc(sizeof(save_t));
|
||||||
|
*save = (save_t) {
|
||||||
|
.request = request,
|
||||||
|
};
|
||||||
|
tf_ssb_run_work(ssb, _httpd_endpoint_save_work, _httpd_endpoint_save_after_work, save);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _delete_t
|
||||||
|
{
|
||||||
|
tf_http_request_t* request;
|
||||||
|
const char* session;
|
||||||
|
int response;
|
||||||
|
} delete_t;
|
||||||
|
|
||||||
|
static void _httpd_endpoint_delete_work(tf_ssb_t* ssb, void* user_data)
|
||||||
|
{
|
||||||
|
delete_t* delete = user_data;
|
||||||
|
tf_http_request_t* request = delete->request;
|
||||||
|
|
||||||
|
JSMallocFunctions funcs = { 0 };
|
||||||
|
tf_get_js_malloc_functions(&funcs);
|
||||||
|
JSRuntime* runtime = JS_NewRuntime2(&funcs, NULL);
|
||||||
|
JSContext* context = JS_NewContext(runtime);
|
||||||
|
|
||||||
|
JSValue jwt = _authenticate_jwt(ssb, context, delete->session);
|
||||||
|
JSValue user = JS_GetPropertyStr(context, jwt, "name");
|
||||||
|
const char* user_string = JS_ToCString(context, user);
|
||||||
|
if (user_string && _is_name_valid(user_string))
|
||||||
|
{
|
||||||
|
user_app_t* user_app = _parse_user_app_from_path(request->path, "/delete");
|
||||||
|
if (user_app)
|
||||||
|
{
|
||||||
|
if (strcmp(user_string, user_app->user) == 0 || (strcmp(user_app->user, "core") == 0 && tf_ssb_db_user_has_permission(ssb, user_string, "administration")))
|
||||||
|
{
|
||||||
|
size_t path_length = strlen("path:") + strlen(user_app->app) + 1;
|
||||||
|
char* app_path = tf_malloc(path_length);
|
||||||
|
snprintf(app_path, path_length, "path:%s", user_app->app);
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
|
changed = tf_ssb_db_remove_value_from_array_property(ssb, user_string, "apps", user_app->app) || changed;
|
||||||
|
changed = tf_ssb_db_remove_property(ssb, user_string, app_path) || changed;
|
||||||
|
delete->response = changed ? 200 : 404;
|
||||||
|
tf_free(app_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete->response = 401;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete->response = 404;
|
||||||
|
}
|
||||||
|
tf_free(user_app);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete->response = 401;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FreeCString(context, user_string);
|
||||||
|
JS_FreeValue(context, user);
|
||||||
|
JS_FreeValue(context, jwt);
|
||||||
|
JS_FreeContext(context);
|
||||||
|
JS_FreeRuntime(runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _httpd_endpoint_delete_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||||
|
{
|
||||||
|
delete_t* delete = user_data;
|
||||||
|
const char* k_payload = tf_http_status_text(delete->response ? delete->response : 404);
|
||||||
|
tf_http_respond(delete->request, delete->response ? delete->response : 404, NULL, 0, k_payload, strlen(k_payload));
|
||||||
|
tf_http_request_unref(delete->request);
|
||||||
|
tf_free((void*)delete->session);
|
||||||
|
tf_free(delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _httpd_endpoint_delete(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);
|
||||||
|
delete_t* delete = tf_malloc(sizeof(delete_t));
|
||||||
|
*delete = (delete_t) {
|
||||||
|
.request = request,
|
||||||
|
.session = tf_http_get_cookie(tf_http_request_get_header(request, "cookie"), "session"),
|
||||||
|
};
|
||||||
|
tf_ssb_run_work(ssb, _httpd_endpoint_delete_work, _httpd_endpoint_delete_after_work, delete);
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
@ -1271,7 +1895,7 @@ static JSValue _authenticate_jwt(tf_ssb_t* ssb, JSContext* context, const char*
|
|||||||
static bool _session_is_authenticated_as_user(JSContext* context, JSValue session)
|
static bool _session_is_authenticated_as_user(JSContext* context, JSValue session)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
JSValue user = JS_GetPropertyStr(context, session, "user");
|
JSValue user = JS_GetPropertyStr(context, session, "name");
|
||||||
const char* user_string = JS_ToCString(context, user);
|
const char* user_string = JS_ToCString(context, user);
|
||||||
result = user_string && strcmp(user_string, "guest") != 0;
|
result = user_string && strcmp(user_string, "guest") != 0;
|
||||||
JS_FreeCString(context, user_string);
|
JS_FreeCString(context, user_string);
|
||||||
@ -1296,7 +1920,7 @@ static bool _is_name_valid(const char* name)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* _make_session_jwt(tf_ssb_t* ssb, const char* name)
|
static const char* _make_session_jwt(JSContext* context, tf_ssb_t* ssb, const char* name)
|
||||||
{
|
{
|
||||||
if (!name || !*name)
|
if (!name || !*name)
|
||||||
{
|
{
|
||||||
@ -1310,7 +1934,6 @@ static const char* _make_session_jwt(tf_ssb_t* ssb, const char* name)
|
|||||||
char header_base64[256];
|
char header_base64[256];
|
||||||
sodium_bin2base64(header_base64, sizeof(header_base64), (uint8_t*)header_json, strlen(header_json), sodium_base64_VARIANT_URLSAFE_NO_PADDING);
|
sodium_bin2base64(header_base64, sizeof(header_base64), (uint8_t*)header_json, strlen(header_json), sodium_base64_VARIANT_URLSAFE_NO_PADDING);
|
||||||
|
|
||||||
JSContext* context = tf_ssb_get_context(ssb);
|
|
||||||
JSValue payload = JS_NewObject(context);
|
JSValue payload = JS_NewObject(context);
|
||||||
JS_SetPropertyStr(context, payload, "name", JS_NewString(context, name));
|
JS_SetPropertyStr(context, payload, "name", JS_NewString(context, name));
|
||||||
JS_SetPropertyStr(context, payload, "exp", JS_NewInt64(context, now.tv_sec * 1000 + now.tv_nsec / 1000000LL + k_refresh_interval));
|
JS_SetPropertyStr(context, payload, "exp", JS_NewInt64(context, now.tv_sec * 1000 + now.tv_nsec / 1000000LL + k_refresh_interval));
|
||||||
@ -1475,27 +2098,39 @@ static void _httpd_endpoint_login_work(tf_ssb_t* ssb, void* user_data)
|
|||||||
|
|
||||||
if (form_register && strcmp(form_register, "1") == 0)
|
if (form_register && strcmp(form_register, "1") == 0)
|
||||||
{
|
{
|
||||||
if (!have_account && _is_name_valid(account_name) && password && confirm && strcmp(password, confirm) == 0 &&
|
bool registered = false;
|
||||||
tf_ssb_db_register_account(ssb, account_name, password))
|
if (!have_account && _is_name_valid(account_name) && password && confirm && strcmp(password, confirm) == 0)
|
||||||
|
{
|
||||||
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
|
registered = tf_ssb_db_register_account(tf_ssb_get_loop(ssb), db, context, account_name, password);
|
||||||
|
tf_ssb_release_db_writer(ssb, db);
|
||||||
|
if (registered)
|
||||||
{
|
{
|
||||||
tf_free((void*)send_session);
|
tf_free((void*)send_session);
|
||||||
send_session = _make_session_jwt(ssb, account_name);
|
send_session = _make_session_jwt(context, ssb, account_name);
|
||||||
may_become_first_admin = true;
|
may_become_first_admin = true;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
if (!registered)
|
||||||
{
|
{
|
||||||
login_error = "Error registering account.";
|
login_error = "Error registering account.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (change && strcmp(change, "1") == 0)
|
else if (change && strcmp(change, "1") == 0)
|
||||||
{
|
{
|
||||||
if (have_account && _is_name_valid(account_name) && new_password && confirm && strcmp(new_password, confirm) == 0 && _verify_password(password, account_passwd) &&
|
bool set = false;
|
||||||
tf_ssb_db_set_account_password(ssb, account_name, new_password))
|
if (have_account && _is_name_valid(account_name) && new_password && confirm && strcmp(new_password, confirm) == 0 && _verify_password(password, account_passwd))
|
||||||
|
{
|
||||||
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
|
set = tf_ssb_db_set_account_password(tf_ssb_get_loop(ssb), db, context, account_name, new_password);
|
||||||
|
tf_ssb_release_db_writer(ssb, db);
|
||||||
|
if (set)
|
||||||
{
|
{
|
||||||
tf_free((void*)send_session);
|
tf_free((void*)send_session);
|
||||||
send_session = _make_session_jwt(ssb, account_name);
|
send_session = _make_session_jwt(context, ssb, account_name);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
if (!set)
|
||||||
{
|
{
|
||||||
login_error = "Error changing password.";
|
login_error = "Error changing password.";
|
||||||
}
|
}
|
||||||
@ -1505,7 +2140,7 @@ static void _httpd_endpoint_login_work(tf_ssb_t* ssb, void* user_data)
|
|||||||
if (have_account && *account_passwd && _verify_password(password, account_passwd))
|
if (have_account && *account_passwd && _verify_password(password, account_passwd))
|
||||||
{
|
{
|
||||||
tf_free((void*)send_session);
|
tf_free((void*)send_session);
|
||||||
send_session = _make_session_jwt(ssb, account_name);
|
send_session = _make_session_jwt(context, ssb, account_name);
|
||||||
may_become_first_admin = true;
|
may_become_first_admin = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1517,7 +2152,7 @@ static void _httpd_endpoint_login_work(tf_ssb_t* ssb, void* user_data)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
tf_free((void*)send_session);
|
tf_free((void*)send_session);
|
||||||
send_session = _make_session_jwt(ssb, "guest");
|
send_session = _make_session_jwt(context, ssb, "guest");
|
||||||
}
|
}
|
||||||
tf_free(post_form_data);
|
tf_free(post_form_data);
|
||||||
}
|
}
|
||||||
@ -1668,6 +2303,17 @@ void tf_httpd_register(JSContext* context)
|
|||||||
tf_http_add_handler(http, "/speedscope/*", _httpd_endpoint_static, NULL, task);
|
tf_http_add_handler(http, "/speedscope/*", _httpd_endpoint_static, NULL, task);
|
||||||
tf_http_add_handler(http, "/static/*", _httpd_endpoint_static, NULL, task);
|
tf_http_add_handler(http, "/static/*", _httpd_endpoint_static, NULL, task);
|
||||||
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, "/&*.sha256", _httpd_endpoint_add_slash, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/&*.sha256/", _httpd_endpoint_static, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/&*.sha256/view", _httpd_endpoint_view, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/&*.sha256/*", _httpd_endpoint_app_blob, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/~{word}/{word}", _httpd_endpoint_add_slash, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/~{word}/{word}/", _httpd_endpoint_static, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/~{word}/{word}/save", _httpd_endpoint_save, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/~{word}/{word}/delete", _httpd_endpoint_delete, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/~{word}/{word}/view", _httpd_endpoint_view, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/~{word}/{word}/*", _httpd_endpoint_app_blob, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/save", _httpd_endpoint_save, 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);
|
||||||
@ -1679,13 +2325,10 @@ void tf_httpd_register(JSContext* context)
|
|||||||
tf_http_add_handler(http, "/login/logout", _httpd_endpoint_logout, NULL, task);
|
tf_http_add_handler(http, "/login/logout", _httpd_endpoint_logout, NULL, task);
|
||||||
tf_http_add_handler(http, "/login", _httpd_endpoint_login, NULL, task);
|
tf_http_add_handler(http, "/login", _httpd_endpoint_login, NULL, task);
|
||||||
|
|
||||||
JS_SetPropertyStr(context, httpd, "handlers", JS_NewObject(context));
|
|
||||||
JS_SetPropertyStr(context, httpd, "all", JS_NewCFunction(context, _httpd_endpoint_all, "all", 2));
|
JS_SetPropertyStr(context, httpd, "all", JS_NewCFunction(context, _httpd_endpoint_all, "all", 2));
|
||||||
JS_SetPropertyStr(context, httpd, "start", JS_NewCFunction(context, _httpd_endpoint_start, "start", 2));
|
JS_SetPropertyStr(context, httpd, "start", JS_NewCFunction(context, _httpd_endpoint_start, "start", 2));
|
||||||
JS_SetPropertyStr(context, httpd, "set_http_redirect", JS_NewCFunction(context, _httpd_set_http_redirect, "set_http_redirect", 1));
|
JS_SetPropertyStr(context, httpd, "set_http_redirect", JS_NewCFunction(context, _httpd_set_http_redirect, "set_http_redirect", 1));
|
||||||
JS_SetPropertyStr(context, httpd, "auth_query", JS_NewCFunction(context, _httpd_auth_query, "auth_query", 1));
|
JS_SetPropertyStr(context, httpd, "auth_query", JS_NewCFunction(context, _httpd_auth_query, "auth_query", 1));
|
||||||
JS_SetPropertyStr(context, httpd, "mime_type_from_magic_bytes", JS_NewCFunction(context, _httpd_mime_type_from_magic_bytes, "mime_type_from_magic_bytes", 1));
|
|
||||||
JS_SetPropertyStr(context, httpd, "mime_type_from_extension", JS_NewCFunction(context, _httpd_mime_type_from_extension, "mime_type_from_extension", 1));
|
|
||||||
JS_SetPropertyStr(context, global, "httpd", httpd);
|
JS_SetPropertyStr(context, global, "httpd", httpd);
|
||||||
JS_FreeValue(context, global);
|
JS_FreeValue(context, global);
|
||||||
}
|
}
|
||||||
|
296
src/main.c
@ -9,6 +9,7 @@
|
|||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "util.js.h"
|
#include "util.js.h"
|
||||||
|
|
||||||
|
#include "ares.h"
|
||||||
#include "backtrace.h"
|
#include "backtrace.h"
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
#include "unzip.h"
|
#include "unzip.h"
|
||||||
@ -34,6 +35,10 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#include "jni.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(_countof)
|
#if !defined(_countof)
|
||||||
#define _countof(a) ((int)(sizeof((a)) / sizeof(*(a))))
|
#define _countof(a) ((int)(sizeof((a)) / sizeof(*(a))))
|
||||||
#endif
|
#endif
|
||||||
@ -43,11 +48,12 @@ struct backtrace_state* g_backtrace_state;
|
|||||||
const char* k_db_path_default = "db.sqlite";
|
const char* k_db_path_default = "db.sqlite";
|
||||||
|
|
||||||
#if !TARGET_OS_IPHONE && !defined(__ANDROID__)
|
#if !TARGET_OS_IPHONE && !defined(__ANDROID__)
|
||||||
static int _tf_command_test(const char* file, int argc, char* argv[]);
|
|
||||||
static int _tf_command_import(const char* file, int argc, char* argv[]);
|
|
||||||
static int _tf_command_export(const char* file, int argc, char* argv[]);
|
static int _tf_command_export(const char* file, int argc, char* argv[]);
|
||||||
|
static int _tf_command_import(const char* file, int argc, char* argv[]);
|
||||||
|
static int _tf_command_publish(const char* file, int argc, char* argv[]);
|
||||||
static int _tf_command_run(const char* file, int argc, char* argv[]);
|
static int _tf_command_run(const char* file, int argc, char* argv[]);
|
||||||
static int _tf_command_sandbox(const char* file, int argc, char* argv[]);
|
static int _tf_command_sandbox(const char* file, int argc, char* argv[]);
|
||||||
|
static int _tf_command_test(const char* file, int argc, char* argv[]);
|
||||||
static int _tf_command_verify(const char* file, int argc, char* argv[]);
|
static int _tf_command_verify(const char* file, int argc, char* argv[]);
|
||||||
static int _tf_command_usage(const char* file);
|
static int _tf_command_usage(const char* file);
|
||||||
|
|
||||||
@ -63,6 +69,7 @@ const command_t k_commands[] = {
|
|||||||
{ "sandbox", _tf_command_sandbox, "Run a sandboxed tildefriends sandbox process (used internally)." },
|
{ "sandbox", _tf_command_sandbox, "Run a sandboxed tildefriends sandbox process (used internally)." },
|
||||||
{ "import", _tf_command_import, "Import apps to SSB." },
|
{ "import", _tf_command_import, "Import apps to SSB." },
|
||||||
{ "export", _tf_command_export, "Export apps from SSB." },
|
{ "export", _tf_command_export, "Export apps from SSB." },
|
||||||
|
{ "publish", _tf_command_publish, "Append a message to a feed." },
|
||||||
{ "verify", _tf_command_verify, "Verify a feed." },
|
{ "verify", _tf_command_verify, "Verify a feed." },
|
||||||
{ "test", _tf_command_test, "Test SSB." },
|
{ "test", _tf_command_test, "Test SSB." },
|
||||||
};
|
};
|
||||||
@ -269,6 +276,121 @@ static int _tf_command_export(const char* file, int argc, char* argv[])
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _tf_published_callback(const char* id, bool verified, bool stored, void* user_data)
|
||||||
|
{
|
||||||
|
if (verified)
|
||||||
|
{
|
||||||
|
if (stored)
|
||||||
|
{
|
||||||
|
tf_printf("Message %s stored.\n", id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tf_printf("Unable to store the message.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tf_printf("Failed to verify the message.\n");
|
||||||
|
}
|
||||||
|
*(int*)user_data = stored ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _tf_command_publish(const char* file, int argc, char* argv[])
|
||||||
|
{
|
||||||
|
const char* user = NULL;
|
||||||
|
const char* identity = NULL;
|
||||||
|
const char* db_path = k_db_path_default;
|
||||||
|
const char* content = NULL;
|
||||||
|
bool show_usage = false;
|
||||||
|
|
||||||
|
while (!show_usage)
|
||||||
|
{
|
||||||
|
static const struct option k_options[] = {
|
||||||
|
{ "user", required_argument, NULL, 'u' },
|
||||||
|
{ "id", required_argument, NULL, 'i' },
|
||||||
|
{ "db-path", required_argument, NULL, 'd' },
|
||||||
|
{ "content", required_argument, NULL, 'c' },
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
int c = getopt_long(argc, argv, "u:i:d:c:h", k_options, NULL);
|
||||||
|
if (c == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '?':
|
||||||
|
case 'h':
|
||||||
|
default:
|
||||||
|
show_usage = true;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
user = optarg;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
identity = optarg;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
db_path = optarg;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
content = optarg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_usage || !user || !identity || !content)
|
||||||
|
{
|
||||||
|
tf_printf("\n%s publish [options]\n\n", file);
|
||||||
|
tf_printf("options:\n");
|
||||||
|
tf_printf(" -u, --user user User owning identity with which to publish.\n");
|
||||||
|
tf_printf(" -i, --id identity Identity with which to publish message.\n");
|
||||||
|
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", k_db_path_default);
|
||||||
|
tf_printf(" -c, --content json JSON content of message to publish.\n");
|
||||||
|
tf_printf(" -h, --help Show this usage information.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = EXIT_FAILURE;
|
||||||
|
tf_printf("Posting %s as account %s belonging to %s...\n", content, identity, user);
|
||||||
|
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
|
||||||
|
uint8_t private_key[512] = { 0 };
|
||||||
|
if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key)))
|
||||||
|
{
|
||||||
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
|
int64_t sequence = 0;
|
||||||
|
char previous[k_id_base64_len] = { 0 };
|
||||||
|
tf_ssb_db_get_latest_message_by_author(ssb, identity, &sequence, previous, sizeof(previous));
|
||||||
|
JSValue content_value = JS_ParseJSON(context, content, strlen(content), NULL);
|
||||||
|
if (!JS_IsException(content_value))
|
||||||
|
{
|
||||||
|
JSValue message = tf_ssb_sign_message(ssb, identity, private_key, content_value, previous, sequence);
|
||||||
|
JSValue message_value = JS_JSONStringify(context, message, JS_NULL, JS_NULL);
|
||||||
|
const char* message_str = JS_ToCString(context, message_value);
|
||||||
|
tf_printf("Posting: %s.\n", message_str);
|
||||||
|
tf_ssb_verify_strip_and_store_message(ssb, message, _tf_published_callback, &result);
|
||||||
|
JS_FreeCString(context, message_str);
|
||||||
|
JS_FreeValue(context, message_value);
|
||||||
|
JS_FreeValue(context, message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tf_printf("Unable to parse content as JSON: ");
|
||||||
|
tf_util_report_error(context, content_value);
|
||||||
|
}
|
||||||
|
JS_FreeValue(context, content_value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tf_printf("Did not find private key for identity %s belonging to %s.\n", identity, user);
|
||||||
|
}
|
||||||
|
tf_ssb_destroy(ssb);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static int _tf_command_verify(const char* file, int argc, char* argv[])
|
static int _tf_command_verify(const char* file, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
const char* identity = NULL;
|
const char* identity = NULL;
|
||||||
@ -278,7 +400,7 @@ static int _tf_command_verify(const char* file, int argc, char* argv[])
|
|||||||
while (!show_usage)
|
while (!show_usage)
|
||||||
{
|
{
|
||||||
static const struct option k_options[] = {
|
static const struct option k_options[] = {
|
||||||
{ "id", required_argument, NULL, 'u' },
|
{ "id", required_argument, NULL, 'i' },
|
||||||
{ "db-path", required_argument, NULL, 'd' },
|
{ "db-path", required_argument, NULL, 'd' },
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
@ -603,14 +725,16 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
|
|||||||
static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
bool show_usage = false;
|
bool show_usage = false;
|
||||||
|
int fd = STDIN_FILENO;
|
||||||
|
|
||||||
while (!show_usage)
|
while (!show_usage)
|
||||||
{
|
{
|
||||||
static const struct option k_options[] = {
|
static const struct option k_options[] = {
|
||||||
|
{ "fd", required_argument, NULL, 'f' },
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
};
|
};
|
||||||
int c = getopt_long(argc, argv, "h", k_options, NULL);
|
int c = getopt_long(argc, argv, "f:h", k_options, NULL);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -622,6 +746,9 @@ static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
|||||||
default:
|
default:
|
||||||
show_usage = true;
|
show_usage = true;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
fd = atoi(optarg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,6 +757,7 @@ static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
|||||||
tf_printf("\nUsage: %s sandbox [options]\n\n", file);
|
tf_printf("\nUsage: %s sandbox [options]\n\n", file);
|
||||||
tf_printf("options:\n");
|
tf_printf("options:\n");
|
||||||
tf_printf(" -h, --help Show this usage information.\n");
|
tf_printf(" -h, --help Show this usage information.\n");
|
||||||
|
tf_printf(" -f, --fd File descriptor with which to communicate with parent process.\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,7 +765,7 @@ static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
|||||||
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
||||||
#endif
|
#endif
|
||||||
tf_task_t* task = tf_task_create();
|
tf_task_t* task = tf_task_create();
|
||||||
tf_task_configure_from_fd(task, STDIN_FILENO);
|
tf_task_configure_from_fd(task, fd);
|
||||||
_shed_privileges();
|
_shed_privileges();
|
||||||
/* The caller will trigger tf_task_activate with a message. */
|
/* The caller will trigger tf_task_activate with a message. */
|
||||||
tf_task_run(task);
|
tf_task_run(task);
|
||||||
@ -685,10 +813,6 @@ static void _startup(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
setenv("UV_USE_IO_URING", "0", 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tf_mem_startup(tracking);
|
tf_mem_startup(tracking);
|
||||||
g_backtrace_state = backtrace_create_state(argv[0], 0, _backtrace_error, NULL);
|
g_backtrace_state = backtrace_create_state(argv[0], 0, _backtrace_error, NULL);
|
||||||
|
|
||||||
@ -716,7 +840,7 @@ static void _startup(int argc, char* argv[])
|
|||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
signal(SIGSYS, _error_handler) == SIG_ERR ||
|
signal(SIGSYS, _error_handler) == SIG_ERR || signal(SIGABRT, _error_handler) == SIG_ERR ||
|
||||||
#endif
|
#endif
|
||||||
signal(SIGSEGV, _error_handler) == SIG_ERR)
|
signal(SIGSEGV, _error_handler) == SIG_ERR)
|
||||||
{
|
{
|
||||||
@ -726,23 +850,143 @@ static void _startup(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
|
static JNIEnv* s_jni_env;
|
||||||
|
|
||||||
|
static void _tf_service_start(int pipe_fd)
|
||||||
|
{
|
||||||
|
tf_printf("_tf_service_start\n");
|
||||||
|
jclass c = (*s_jni_env)->FindClass(s_jni_env, "com/unprompted/tildefriends/TildeFriendsActivity");
|
||||||
|
jmethodID start_sandbox = (*s_jni_env)->GetStaticMethodID(s_jni_env, c, "start_sandbox", "(I)V");
|
||||||
|
(*s_jni_env)->CallStaticVoidMethod(s_jni_env, c, start_sandbox, pipe_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _tf_service_stop()
|
||||||
|
{
|
||||||
|
tf_printf("_tf_service_stop\n");
|
||||||
|
jclass c = (*s_jni_env)->FindClass(s_jni_env, "com/unprompted/tildefriends/TildeFriendsActivity");
|
||||||
|
jmethodID stop_sandbox = (*s_jni_env)->GetStaticMethodID(s_jni_env, c, "stop_sandbox", "()V");
|
||||||
|
(*s_jni_env)->CallStaticVoidMethod(s_jni_env, c, stop_sandbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
static jint _tf_server_main(JNIEnv* env, jobject this_object, jstring files_dir, jstring apk_path, jstring out_port_file_path, jobject connectivity_manager)
|
||||||
|
{
|
||||||
|
s_jni_env = env;
|
||||||
|
|
||||||
|
tf_printf("This is tf_server_main main.\n");
|
||||||
|
_startup(0, (char*[]) { NULL });
|
||||||
|
tf_printf("That was startup.\n");
|
||||||
|
|
||||||
|
ares_library_init_android(connectivity_manager);
|
||||||
|
ares_library_init(0);
|
||||||
|
|
||||||
|
const char* files = (*env)->GetStringUTFChars(env, files_dir, NULL);
|
||||||
|
const char* apk = (*env)->GetStringUTFChars(env, apk_path, NULL);
|
||||||
|
const char* out_port_file = (*env)->GetStringUTFChars(env, out_port_file_path, NULL);
|
||||||
|
|
||||||
|
tf_printf("FILES = %s\n", files);
|
||||||
|
tf_printf("APK = %s\n", apk);
|
||||||
|
tf_printf("OUT_PORT = %s\n", out_port_file);
|
||||||
|
|
||||||
|
int result = uv_chdir(files);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
tf_printf("uv_chdir: %s\n", uv_strerror(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t port_file_arg_length = strlen(out_port_file) + strlen("out_http_port_file=") + 1;
|
||||||
|
char* port_file_arg = alloca(port_file_arg_length);
|
||||||
|
snprintf(port_file_arg, port_file_arg_length, "out_http_port_file=%s", out_port_file);
|
||||||
|
|
||||||
|
const char* args[] = {
|
||||||
|
"run",
|
||||||
|
"-z",
|
||||||
|
apk,
|
||||||
|
"-a",
|
||||||
|
port_file_arg,
|
||||||
|
"-p",
|
||||||
|
"0",
|
||||||
|
};
|
||||||
|
|
||||||
|
tf_task_set_android_service_callbacks(_tf_service_start, _tf_service_stop);
|
||||||
|
result = _tf_command_run(apk, _countof(args), (char**)args);
|
||||||
|
tf_task_set_android_service_callbacks(NULL, NULL);
|
||||||
|
|
||||||
|
(*env)->ReleaseStringUTFChars(env, files_dir, files);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, apk_path, apk);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, out_port_file_path, out_port_file);
|
||||||
|
|
||||||
|
ares_library_cleanup();
|
||||||
|
tf_mem_shutdown();
|
||||||
|
tf_printf("tf_server_main finished with %d.", result);
|
||||||
|
|
||||||
|
s_jni_env = NULL;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jint _tf_sandbox_main(JNIEnv* env, jobject this_object, int pipe_fd)
|
||||||
|
{
|
||||||
|
s_jni_env = env;
|
||||||
|
|
||||||
|
tf_printf("This is tf_sandbox_main main (fd=%d).\n", pipe_fd);
|
||||||
|
_startup(0, (char*[]) { NULL });
|
||||||
|
tf_printf("That was startup.\n");
|
||||||
|
|
||||||
|
char fd[32] = { 0 };
|
||||||
|
snprintf(fd, sizeof(fd), "%d", pipe_fd);
|
||||||
|
const char* args[] = {
|
||||||
|
"sandbox",
|
||||||
|
"-f",
|
||||||
|
fd,
|
||||||
|
};
|
||||||
|
|
||||||
|
int result = _tf_command_sandbox(NULL, _countof(args), (char**)args);
|
||||||
|
|
||||||
|
tf_mem_shutdown();
|
||||||
|
tf_printf("tf_sandbox_main finished with %d.", result);
|
||||||
|
|
||||||
|
s_jni_env = NULL;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||||
|
{
|
||||||
|
tf_printf("JNI_Onload called.\n");
|
||||||
|
JNIEnv* env;
|
||||||
|
if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK)
|
||||||
|
{
|
||||||
|
tf_printf("Failed to get JNI environment.\n");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
tf_printf("Finding class.\n");
|
||||||
|
jclass c = (*env)->FindClass(env, "com/unprompted/tildefriends/TildeFriendsActivity");
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
tf_printf("Failed to find TildeFriendsActivity class.\n");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
tf_printf("Registering method.\n");
|
||||||
|
static const JNINativeMethod methods[] = {
|
||||||
|
{ "tf_server_main", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/net/ConnectivityManager;)I", _tf_server_main },
|
||||||
|
{ "tf_sandbox_main", "(I)I", _tf_sandbox_main },
|
||||||
|
};
|
||||||
|
int result = (*env)->RegisterNatives(env, c, methods, (int)_countof(methods));
|
||||||
|
if (result != JNI_OK)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ares_library_init_jvm(vm);
|
||||||
|
|
||||||
|
tf_printf("Done.\n");
|
||||||
|
return JNI_VERSION_1_6;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
_startup(argc, argv);
|
tf_printf("Welcome to Tilde Friends. This is not the way to run on Android.\n");
|
||||||
int result = -1;
|
return EXIT_FAILURE;
|
||||||
if (argc > 1)
|
|
||||||
{
|
|
||||||
if (strcmp(argv[1], "run") == 0)
|
|
||||||
{
|
|
||||||
result = _tf_command_run(argv[0], argc - 1, argv + 1);
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[1], "sandbox") == 0)
|
|
||||||
{
|
|
||||||
result = _tf_command_sandbox(argv[0], argc - 1, argv + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tf_mem_shutdown();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
#elif TARGET_OS_IPHONE
|
#elif TARGET_OS_IPHONE
|
||||||
void tf_run_thread_start(const char* zip_path)
|
void tf_run_thread_start(const char* zip_path)
|
||||||
@ -769,6 +1013,7 @@ void tf_run_thread_start(const char* zip_path)
|
|||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
_startup(argc, argv);
|
_startup(argc, argv);
|
||||||
|
ares_library_init(0);
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (argc >= 2)
|
if (argc >= 2)
|
||||||
@ -789,6 +1034,7 @@ int main(int argc, char* argv[])
|
|||||||
result = _tf_command_run(argv[0], argc, argv);
|
result = _tf_command_run(argv[0], argc, argv);
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
|
ares_library_cleanup();
|
||||||
tf_mem_shutdown();
|
tf_mem_shutdown();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,14 @@
|
|||||||
|
|
||||||
#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 <string.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <string.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>
|
||||||
|
|
||||||
|