Compare commits
76 Commits
v0.0.22
...
b222dc0ca8
Author | SHA1 | Date | |
---|---|---|---|
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 |
40
.fdroid.yml
40
.fdroid.yml
@ -1,40 +0,0 @@
|
|||||||
Categories:
|
|
||||||
- Internet
|
|
||||||
License: MIT
|
|
||||||
|
|
||||||
AutoName: tildefriends
|
|
||||||
AuthorName: Cory McWilliams
|
|
||||||
AuthorEmail: cory@tildefriends.net
|
|
||||||
|
|
||||||
RepoType: git
|
|
||||||
Repo: https://dev.tildefriends.net/cory/tildefriends.git
|
|
||||||
|
|
||||||
Builds:
|
|
||||||
- versionName: 0.0.21-wip
|
|
||||||
versionCode: 22
|
|
||||||
commit: 09b6a00731d45fa160b23a2c44be6def98d92d6a
|
|
||||||
subdir: src/android
|
|
||||||
submodules: true
|
|
||||||
sudo:
|
|
||||||
- apt-get update
|
|
||||||
- apt-get install -y ant make zip
|
|
||||||
androidupdate:
|
|
||||||
- no
|
|
||||||
scandelete:
|
|
||||||
- deps/libuv/docs/src/static/diagrams.key/Index.zip
|
|
||||||
- deps/openssl_src/cloudflare-quiche/*
|
|
||||||
- deps/openssl_src/fuzz/*
|
|
||||||
- deps/openssl_src/gost-engine/*
|
|
||||||
- deps/openssl_src/test/*
|
|
||||||
- deps/openssl_src/tlslite-ng/*
|
|
||||||
prebuild:
|
|
||||||
- sdkmanager "platforms;android-34" "build-tools;34.0.0"
|
|
||||||
build:
|
|
||||||
- mkdir bin/
|
|
||||||
- ANDROID_SDK=$$SDK$$ ANDROID_NDK=$$NDK$$ ANDROID_NDK_ROOT=$$NDK$$ make -C ../../ -j`nproc` fdroid
|
|
||||||
ndk: r26d
|
|
||||||
|
|
||||||
AutoUpdateMode: Version ^v[0-9\.]+$
|
|
||||||
UpdateCheckMode: Tags
|
|
||||||
CurrentVersion: 0.0.21-wip
|
|
||||||
CurrentVersionCode: 22
|
|
@ -5,11 +5,34 @@ on: [push]
|
|||||||
jobs:
|
jobs:
|
||||||
Build-All:
|
Build-All:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
valid_volumes: ['/opt/keys']
|
||||||
|
volumes:
|
||||||
|
- /opt/keys:/opt/keys
|
||||||
steps:
|
steps:
|
||||||
- name: check out code
|
- name: check out code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- run: sudo apt update && sudo apt install -y doxygen graphviz mingw-w64
|
- run: ln -s /opt/keys .keys
|
||||||
- run: make all -j`nproc` docs
|
- 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 .
|
- 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
|
||||||
|
64
GNUmakefile
64
GNUmakefile
@ -3,12 +3,14 @@
|
|||||||
MAKEFLAGS += --warn-undefined-variables
|
MAKEFLAGS += --warn-undefined-variables
|
||||||
MAKEFLAGS += --no-builtin-rules
|
MAKEFLAGS += --no-builtin-rules
|
||||||
|
|
||||||
VERSION_CODE := 26
|
VERSION_CODE := 28
|
||||||
VERSION_NUMBER := 0.0.22
|
VERSION_NUMBER := 0.0.24-wip
|
||||||
VERSION_NAME := Get born soon.
|
VERSION_NAME := Honey bunches of boats.
|
||||||
|
|
||||||
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3460100.zip
|
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3460100.zip
|
||||||
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.17.0/bundletool-all-1.17.0.jar
|
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.17.0/bundletool-all-1.17.0.jar
|
||||||
|
APPIMAGETOOL_URL := https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||||
|
APPIMAGETOOL_MD5 := e989fadfc4d685fd3d6aeeb9b525d74d out/appimagetool
|
||||||
|
|
||||||
PROJECT = tildefriends
|
PROJECT = tildefriends
|
||||||
BUILD_DIR ?= out
|
BUILD_DIR ?= out
|
||||||
@ -35,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 += \
|
||||||
@ -225,6 +228,9 @@ $(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/inc
|
|||||||
$(IOSSIM_TARGETS): LDFLAGS += -Ldeps/openssl/ios/iossimulator-xcrun/usr/local/lib
|
$(IOSSIM_TARGETS): LDFLAGS += -Ldeps/openssl/ios/iossimulator-xcrun/usr/local/lib
|
||||||
|
|
||||||
ifeq ($(UNAME_M),x86_64)
|
ifeq ($(UNAME_M),x86_64)
|
||||||
|
ifeq ($(UNAME_S),Linux)
|
||||||
|
all: appimage
|
||||||
|
endif
|
||||||
ifneq ($(UNAME_S),Haiku)
|
ifneq ($(UNAME_S),Haiku)
|
||||||
out/debug/tildefriends: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
|
out/debug/tildefriends: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
|
||||||
out/debug/tildefriends: LDFLAGS += -fsanitize=address -fsanitize=undefined
|
out/debug/tildefriends: LDFLAGS += -fsanitize=address -fsanitize=undefined
|
||||||
@ -500,9 +506,13 @@ $(UV_OBJS): CFLAGS += \
|
|||||||
-Wno-unused-but-set-parameter \
|
-Wno-unused-but-set-parameter \
|
||||||
-Wno-unused-but-set-variable \
|
-Wno-unused-but-set-variable \
|
||||||
-Wno-unused-result \
|
-Wno-unused-result \
|
||||||
-Wno-unused-variable
|
-Wno-unused-variable \
|
||||||
|
-Wno-nonnull
|
||||||
$(UV_OBJS): CFLAGS += -fno-lto
|
$(UV_OBJS): CFLAGS += -fno-lto
|
||||||
$(filter out/win%,$(UV_OBJS)): CFLAGS += -Wno-cast-function-type
|
$(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
|
||||||
@ -842,7 +852,7 @@ PACKAGE_DIRS := \
|
|||||||
deps/prettier/ \
|
deps/prettier/ \
|
||||||
deps/lit/
|
deps/lit/
|
||||||
|
|
||||||
RAW_FILES := $(sort $(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
|
||||||
@ -1066,14 +1076,36 @@ $(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
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_DIR)
|
rm -rf $(BUILD_DIR)
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
||||||
dist: release-apk iosrelease-ipa aab $(if $(HAVE_WIN), out/winrelease/tildefriends.standalone.exe) out/TildeFriends-release.fdroid.apk
|
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* \
|
||||||
@ -1090,9 +1122,15 @@ dist: release-apk iosrelease-ipa aab $(if $(HAVE_WIN), out/winrelease/tildefrien
|
|||||||
--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"
|
||||||
@ -1101,8 +1139,12 @@ dist: release-apk iosrelease-ipa aab $(if $(HAVE_WIN), out/winrelease/tildefrien
|
|||||||
@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
|
@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
|
@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
|
||||||
|
23
README.md
23
README.md
@ -19,8 +19,27 @@ 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` releases are all-inclusive.
|
||||||
|
|
||||||
|
The gitea `Source Code (ZIP)` and `Source Code (TAR.GZ)` are missing
|
||||||
|
dependencies, so don't use those.
|
||||||
|
|
||||||
|
1. On Linux only, system OpenSSL libraries (`libssl-dev`, in debian-speak) is
|
||||||
|
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
|
||||||
|
@ -28,7 +28,10 @@ function global_settings_set(key, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function title_case(name) {
|
function title_case(name) {
|
||||||
return name.split('_').map(x => x.charAt(0).toUpperCase() + x.substring(1)).join(' ');
|
return name
|
||||||
|
.split('_')
|
||||||
|
.map((x) => x.charAt(0).toUpperCase() + x.substring(1))
|
||||||
|
.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('load', function () {
|
window.addEventListener('load', function () {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🪪",
|
"emoji": "🪪",
|
||||||
"previous": "&de7q4A59auHP/34bXgeNH05JZoxsGr5TjwXPvehWH30=.sha256"
|
"previous": "&zxsmzdLKsiG/WZt/Gw7JOxepgypoktNNbIyWiyFiJVc=.sha256"
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ tfrpc.register(async function reload() {
|
|||||||
|
|
||||||
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>
|
||||||
@ -123,7 +124,7 @@ async function main() {
|
|||||||
) => `<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}
|
${id}${id == server_id ? ' <div class="w3-tag w3-theme-l4 w3-round">🖥 local server</div>' : ''}
|
||||||
</li>`
|
</li>`
|
||||||
)
|
)
|
||||||
.join('\n') +
|
.join('\n') +
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🐌",
|
"emoji": "🐌",
|
||||||
"previous": "&xsmsLytB3VvoHphiFHZGGEvrCfTEVGXrGwobGTIYFPQ=.sha256"
|
"previous": "&PK+UixgYQEYFKKPJ3BVacSKaDRRjiNO6M/fmgzDJaRM=.sha256"
|
||||||
}
|
}
|
||||||
|
@ -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">
|
||||||
${(this.message.votes || []).map(
|
<div
|
||||||
(vote) => html`
|
class="w3-button w3-bar w3-padding-small"
|
||||||
<span
|
@click=${this.show_reactions}
|
||||||
title="${this.users[vote.author]?.name ?? vote.author} ${new Date(
|
>
|
||||||
vote.timestamp
|
${(this.message.votes || []).map(
|
||||||
)}"
|
(vote) => html`
|
||||||
>
|
<span
|
||||||
${normalize_expression(vote.content.vote.expression)}
|
class="w3-bar-item w3-padding-small"
|
||||||
</span>
|
title="${this.users[vote.author]?.name ??
|
||||||
`
|
vote.author} ${new Date(vote.timestamp)}"
|
||||||
)}
|
>
|
||||||
|
${normalize_expression(vote.content.vote.expression)}
|
||||||
|
</span>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,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"
|
||||||
|
@ -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>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "👋",
|
"emoji": "👋",
|
||||||
"previous": "&W5aJp2DgOW5rQ0AOIC9Ut3DpsahPrO6PjkJ1PQbNRdM=.sha256"
|
"previous": "&UmqHvALMxDC7ao/VO8p33CLRpmHiEXOk+8cCVMOJRLU=.sha256"
|
||||||
}
|
}
|
||||||
|
78
apps/welcome/appimage.svg
Normal file
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
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 |
@ -68,6 +68,21 @@
|
|||||||
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> Code</a
|
||||||
>
|
>
|
||||||
|
<p>
|
||||||
|
<a
|
||||||
|
class="w3-button w3-black w3-round-medium w3-padding-small"
|
||||||
|
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-black w3-round-medium w3-padding-small"
|
||||||
|
href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
||||||
|
>
|
||||||
|
<img src="appimage.svg" style="height: 2em; margin: 0" />
|
||||||
|
Get Linux 64-bit AppImage
|
||||||
|
</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" />
|
||||||
@ -244,7 +259,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 +285,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>
|
||||||
|
@ -77,7 +77,8 @@ const k_global_settings = {
|
|||||||
peer_exchange: {
|
peer_exchange: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default_value: false,
|
default_value: false,
|
||||||
description: 'Enable discovery of, sharing of, and connecting to internet peer strangers, including announcing this instance.',
|
description:
|
||||||
|
'Enable discovery of, sharing of, and connecting to internet peer strangers, including announcing this instance.',
|
||||||
},
|
},
|
||||||
account_registration: {
|
account_registration: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
@ -1350,8 +1351,4 @@ function storePermission(user, packageOwner, packageName, permission, allow) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {invoke, getSessionProcessBlob};
|
||||||
gGlobalSettings as globalSettings,
|
|
||||||
invoke,
|
|
||||||
getSessionProcessBlob,
|
|
||||||
};
|
|
||||||
|
@ -21,14 +21,14 @@
|
|||||||
}:
|
}:
|
||||||
pkgs.stdenv.mkDerivation rec {
|
pkgs.stdenv.mkDerivation rec {
|
||||||
pname = "tildefriends";
|
pname = "tildefriends";
|
||||||
version = "0.0.22";
|
version = "0.0.23";
|
||||||
|
|
||||||
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-0x4LJXtMUxBsWEOoWAaQlStTfvqUf4Qs/5vJZ2EvBpY=";
|
hash = "sha256-ukZpi+BXRTFGbdvd5ApmctTo8bjtPJMHjqFPgVSyBWU=";
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2
deps/c-ares
vendored
2
deps/c-ares
vendored
Submodule deps/c-ares updated: caffa5ffb3...27b98d96ef
2
deps/codemirror/cm6.js
vendored
2
deps/codemirror/cm6.js
vendored
File diff suppressed because one or more lines are too long
244
deps/codemirror_src/package-lock.json
generated
vendored
244
deps/codemirror_src/package-lock.json
generated
vendored
@ -19,9 +19,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/autocomplete": {
|
"node_modules/@codemirror/autocomplete": {
|
||||||
"version": "6.18.0",
|
"version": "6.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.1.tgz",
|
||||||
"integrity": "sha512-5DbOvBbY4qW5l57cjDsmmpDh3/TeK1vXfTHa+BUMrRzdWdcxKZ4U4V7vQaTtOpApNU4kLS4FQ6cINtLg245LXA==",
|
"integrity": "sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
@ -37,9 +37,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/commands": {
|
"node_modules/@codemirror/commands": {
|
||||||
"version": "6.6.0",
|
"version": "6.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.6.2.tgz",
|
||||||
"integrity": "sha512-qnY+b7j1UNcTS31Eenuc/5YJB6gQOzkUoNmJQc0rznwqSRpeaWWpjkWy2C/MPTcePpsKJEM26hXrOXl1+nceXg==",
|
"integrity": "sha512-Fq7eWOl1Rcbrfn6jD8FPCj9Auaxdm5nIK5RYOeW7ughnd/rY5AmPg6b+CfsG39ZHdwiwe8lde3q8uR7CF5S0yQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
@ -49,16 +49,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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",
|
"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": {
|
||||||
@ -104,9 +104,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
@ -118,9 +118,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lint": {
|
"node_modules/@codemirror/lint": {
|
||||||
"version": "6.8.1",
|
"version": "6.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.2.tgz",
|
||||||
"integrity": "sha512-IZ0Y7S4/bpaunwggW2jYqwLuHj0QtESf5xcROewY6+lDNwZ/NzvR4t+vpYgg9m7V8UXLPYqG+lu3DF470E5Oxg==",
|
"integrity": "sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
@ -158,9 +158,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/view": {
|
"node_modules/@codemirror/view": {
|
||||||
"version": "6.33.0",
|
"version": "6.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.33.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.1.tgz",
|
||||||
"integrity": "sha512-AroaR3BvnjRW8fiZBalAaK+ZzB5usGgI014YKElYZvQdNH5ZIidHlO+cyf/2rWzyBFRkvG6VhiXeAEbC53P2YQ==",
|
"integrity": "sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.4.0",
|
"@codemirror/state": "^6.4.0",
|
||||||
@ -233,15 +233,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/common": {
|
"node_modules/@lezer/common": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.2.tgz",
|
||||||
"integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==",
|
"integrity": "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw==",
|
||||||
"license": "MIT"
|
"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",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
@ -270,9 +270,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/javascript": {
|
"node_modules/@lezer/javascript": {
|
||||||
"version": "1.4.17",
|
"version": "1.4.18",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.17.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.18.tgz",
|
||||||
"integrity": "sha512-bYW4ctpyGK+JMumDApeUzuIezX01H76R1foD6LcRX224FWfyYit/HYxiPGDjXXe/wQWASjCvVGoukTH68+0HIA==",
|
"integrity": "sha512-Y8BeHOt4LtcxJgXwadtfSeWPrh0XzklcCHnCVT+vOsxqH4gWmunP2ykX+VVOlM/dusyVyiNfG3lv0f10UK+mgA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
@ -301,15 +301,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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",
|
"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"
|
||||||
},
|
},
|
||||||
@ -349,9 +348,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/pluginutils": {
|
"node_modules/@rollup/pluginutils": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz",
|
||||||
"integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==",
|
"integrity": "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "^1.0.0",
|
"@types/estree": "^1.0.0",
|
||||||
@ -371,9 +370,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
|
||||||
"integrity": "sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA==",
|
"integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -384,9 +383,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm64": {
|
"node_modules/@rollup/rollup-android-arm64": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz",
|
||||||
"integrity": "sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA==",
|
"integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -397,9 +396,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz",
|
||||||
"integrity": "sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA==",
|
"integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -410,9 +409,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-x64": {
|
"node_modules/@rollup/rollup-darwin-x64": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz",
|
||||||
"integrity": "sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg==",
|
"integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -423,9 +422,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz",
|
||||||
"integrity": "sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA==",
|
"integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -436,9 +435,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz",
|
||||||
"integrity": "sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w==",
|
"integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -449,9 +448,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz",
|
||||||
"integrity": "sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w==",
|
"integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -462,9 +461,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz",
|
||||||
"integrity": "sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw==",
|
"integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -475,9 +474,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz",
|
||||||
"integrity": "sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg==",
|
"integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@ -488,9 +487,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz",
|
||||||
"integrity": "sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg==",
|
"integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
@ -501,9 +500,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz",
|
||||||
"integrity": "sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw==",
|
"integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@ -514,9 +513,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz",
|
||||||
"integrity": "sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg==",
|
"integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -527,9 +526,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz",
|
||||||
"integrity": "sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ==",
|
"integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -540,9 +539,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz",
|
||||||
"integrity": "sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ==",
|
"integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -553,9 +552,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz",
|
||||||
"integrity": "sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg==",
|
"integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@ -566,9 +565,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz",
|
||||||
"integrity": "sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ==",
|
"integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -579,9 +578,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"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"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/resolve": {
|
"node_modules/@types/resolve": {
|
||||||
@ -610,18 +609,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/builtin-modules": {
|
|
||||||
"version": "3.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
|
|
||||||
"integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/codemirror": {
|
"node_modules/codemirror": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
|
||||||
@ -700,21 +687,6 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-builtin-module": {
|
|
||||||
"version": "3.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
|
|
||||||
"integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"builtin-modules": "^3.3.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.15.1",
|
"version": "2.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
|
||||||
@ -782,12 +754,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.21.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz",
|
||||||
"integrity": "sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ==",
|
"integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.5"
|
"@types/estree": "1.0.6"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
@ -797,22 +769,22 @@
|
|||||||
"npm": ">=8.0.0"
|
"npm": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-android-arm-eabi": "4.21.0",
|
"@rollup/rollup-android-arm-eabi": "4.24.0",
|
||||||
"@rollup/rollup-android-arm64": "4.21.0",
|
"@rollup/rollup-android-arm64": "4.24.0",
|
||||||
"@rollup/rollup-darwin-arm64": "4.21.0",
|
"@rollup/rollup-darwin-arm64": "4.24.0",
|
||||||
"@rollup/rollup-darwin-x64": "4.21.0",
|
"@rollup/rollup-darwin-x64": "4.24.0",
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": "4.21.0",
|
"@rollup/rollup-linux-arm-gnueabihf": "4.24.0",
|
||||||
"@rollup/rollup-linux-arm-musleabihf": "4.21.0",
|
"@rollup/rollup-linux-arm-musleabihf": "4.24.0",
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.21.0",
|
"@rollup/rollup-linux-arm64-gnu": "4.24.0",
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.21.0",
|
"@rollup/rollup-linux-arm64-musl": "4.24.0",
|
||||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.21.0",
|
"@rollup/rollup-linux-powerpc64le-gnu": "4.24.0",
|
||||||
"@rollup/rollup-linux-riscv64-gnu": "4.21.0",
|
"@rollup/rollup-linux-riscv64-gnu": "4.24.0",
|
||||||
"@rollup/rollup-linux-s390x-gnu": "4.21.0",
|
"@rollup/rollup-linux-s390x-gnu": "4.24.0",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.21.0",
|
"@rollup/rollup-linux-x64-gnu": "4.24.0",
|
||||||
"@rollup/rollup-linux-x64-musl": "4.21.0",
|
"@rollup/rollup-linux-x64-musl": "4.24.0",
|
||||||
"@rollup/rollup-win32-arm64-msvc": "4.21.0",
|
"@rollup/rollup-win32-arm64-msvc": "4.24.0",
|
||||||
"@rollup/rollup-win32-ia32-msvc": "4.21.0",
|
"@rollup/rollup-win32-ia32-msvc": "4.24.0",
|
||||||
"@rollup/rollup-win32-x64-msvc": "4.21.0",
|
"@rollup/rollup-win32-x64-msvc": "4.24.0",
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -894,9 +866,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.31.6",
|
"version": "5.34.1",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.34.1.tgz",
|
||||||
"integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==",
|
"integrity": "sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
2
deps/libuv
vendored
2
deps/libuv
vendored
Submodule deps/libuv updated: e9f29cb984...d2e56a5e8d
2
deps/openssl_src
vendored
2
deps/openssl_src
vendored
Submodule deps/openssl_src updated: db2ac4f6eb...fb7fab9fa6
63
docs/cheatsheet.md
Normal file
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)
|
267
docs/guide.md
267
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()));
|
|
||||||
});
|
|
||||||
|
|
||||||
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="<h1 style="color: #fff">Welcome, visitor #1!</h1>"></iframe>
|
||||||
terminal.print("Hello, world!");
|
|
||||||
|
|
||||||
## API Documentation
|
### Explanation
|
||||||
|
|
||||||
The Tilde Friends API is very much evolving.
|
Just as pure browser apps have access to `localStorage`, Tilde Friends apps have access to key-value storage on the server.
|
||||||
|
|
||||||
All currently registered methods can be explored in the
|
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.
|
||||||
[documentation](https://www.tildefriends.net/~cory/documentation) app.
|
|
||||||
|
|
||||||
All browser-facing methods are implemented in [client.js](core/client.js).
|
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.
|
||||||
Most process-related methods are implemented in [core.js](core/core.js).
|
|
||||||
|
|
||||||
Higher-level behaviors are often implemented within library-style apps
|
## Example 3: Files
|
||||||
themselves and are beyond the scope of this document.
|
|
||||||
|
|
||||||
### Terminal
|
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.
|
||||||
|
|
||||||
All interaction with a human user is through a terminal-like interface. Though
|
### app.js
|
||||||
it is somewhat limiting, it makes simple things easy, and it is possible to
|
|
||||||
construct complicated interfaces by creating and interacting with an iframe.
|
|
||||||
|
|
||||||
#### terminal.print(arguments...)
|
```
|
||||||
|
async function main() {
|
||||||
|
let html = utf8Decode(await getFile('index.html'));
|
||||||
|
app.setDocument(html);
|
||||||
|
}
|
||||||
|
|
||||||
Print to the terminal. Arguments and lists are recursively expanded. Numerous
|
main();
|
||||||
special values are supported as implemented in client.cs.
|
```
|
||||||
|
|
||||||
// Create a link.
|
### index.html
|
||||||
terminal.print({href: "http://www.tildefriends.net/", value: "Tilde Friends!"});
|
|
||||||
|
|
||||||
// Create an iframe.
|
```
|
||||||
terminal.print({iframe: "<b>Hello, world!</b>", width: 640, height: 480});
|
<html>
|
||||||
|
<head>
|
||||||
|
<script type="module" src="script.js"></script>
|
||||||
|
</head>
|
||||||
|
<body style="color: #fff">
|
||||||
|
<h1>File Test</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
// Use style.
|
### script.js
|
||||||
terminal.print({style: "color: #f00", value: "Hello, world!"});
|
|
||||||
|
|
||||||
// Create a link that when clicked will act as if the user typed a command.
|
```
|
||||||
terminal.print({command: "exit", value: "Get out of here."});
|
window.addEventListener('load', function() {
|
||||||
|
document.body.appendChild(document.createTextNode('Hello, world');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
#### terminal.clear()
|
### Output
|
||||||
|
|
||||||
Clears the terminal output.
|
<iframe srcdoc="<body style="color: #fff"><h1>File Test</h1>Hello, world!</body>"></iframe>
|
||||||
|
|
||||||
#### terminal.readLine()
|
### Explanation
|
||||||
|
|
||||||
Read a line of input from the user.
|
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.
|
||||||
|
|
||||||
#### terminal.setEcho(echo)
|
## Example 4: Remote Procedure Call
|
||||||
|
|
||||||
Controls whether the terminal will automatically echo user input. Defaults to true.
|
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.
|
||||||
|
|
||||||
#### terminal.setPrompt(prompt)
|
### app.js
|
||||||
|
|
||||||
Sets the terminal prompt. The default is ">".
|
```
|
||||||
|
import * as tf from '/tfrpc.js';
|
||||||
|
|
||||||
#### terminal.setTitle(title)
|
function sum() {
|
||||||
|
let s = 0
|
||||||
|
for (let x of arguments) {
|
||||||
|
s += x;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
tf.register(sum);
|
||||||
|
|
||||||
Sets the browser window/tab title.
|
async function main() {
|
||||||
|
app.setDocument(utf8Decode(await getFile('index.html')));
|
||||||
|
}
|
||||||
|
main();
|
||||||
|
```
|
||||||
|
|
||||||
#### terminal.split(terminalList)
|
### index.html
|
||||||
|
|
||||||
Reconfigures the terminal layout, potentially into multiple split panes.
|
```
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1 id='result'>Calculating...</h1>
|
||||||
|
</body>
|
||||||
|
<script type="module" src="script.js"></script>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
terminal.split([
|
### script.js
|
||||||
{
|
|
||||||
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)
|
```
|
||||||
|
import * as tf from '/static/tfrpc.js';
|
||||||
|
|
||||||
Directs subsequent output to the named terminal.
|
window.addEventListener('load', async function() {
|
||||||
|
document.getElementById('result').innerText = await tf.rpc.sum(1, 2, 3);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
#### terminal.postMessageToIframe(iframeName, message)
|
### Output
|
||||||
|
|
||||||
Sends a message to the iframe that was created with the given name, using the
|
<iframe srcdoc="<body style="color: #fff"><h1>6</h1></body>"></iframe>
|
||||||
browser's window.postMessage.
|
|
||||||
|
|
||||||
### Database
|
### Explanation
|
||||||
|
|
||||||
Tilde Friends uses lmdb as a basic key value store. Keys and values are all
|
Here the browser makes an asynchronous call to the server to do some basic math and update its DOM with the result.
|
||||||
expected to be of type String. Each application gets its own isolated
|
|
||||||
database.
|
|
||||||
|
|
||||||
#### database.get(key)
|
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.
|
||||||
|
|
||||||
Retrieve the database value associated with the given key.
|
## Conclusion
|
||||||
|
|
||||||
#### database.set(key, value)
|
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 database value for the given key, overwriting any existing value.
|
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.
|
||||||
|
|
||||||
#### 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.
|
|
||||||
|
64
docs/vision.md
Normal file
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.
|
11
metadata/en-US/changelogs/27.txt
Normal file
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.
|
4
package-lock.json
generated
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,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.unprompted.tildefriends"
|
package="com.unprompted.tildefriends"
|
||||||
android:versionCode="26"
|
android:versionCode="28"
|
||||||
android:versionName="0.0.22">
|
android:versionName="0.0.24-wip">
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<application
|
<application
|
||||||
|
@ -11,6 +11,7 @@ import android.net.ConnectivityManager;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.os.FileObserver;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
@ -42,12 +43,6 @@ import java.io.File;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.file.FileSystems;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.nio.file.StandardWatchEventKinds;
|
|
||||||
import java.nio.file.WatchEvent;
|
|
||||||
import java.nio.file.WatchKey;
|
|
||||||
import java.nio.file.WatchService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class TildeFriendsActivity extends Activity {
|
public class TildeFriendsActivity extends Activity {
|
||||||
@ -55,9 +50,9 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
TildeFriendsWebView web_view;
|
TildeFriendsWebView web_view;
|
||||||
String base_url;
|
String base_url;
|
||||||
String port_file_path;
|
String port_file_path;
|
||||||
Thread thread;
|
|
||||||
Thread server_thread;
|
Thread server_thread;
|
||||||
ServiceConnection service_connection;
|
ServiceConnection service_connection;
|
||||||
|
FileObserver observer;
|
||||||
|
|
||||||
private ValueCallback<Uri[]> upload_message;
|
private ValueCallback<Uri[]> upload_message;
|
||||||
private final static int FILECHOOSER_RESULT = 1;
|
private final static int FILECHOOSER_RESULT = 1;
|
||||||
@ -95,56 +90,9 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
|
|
||||||
TildeFriendsActivity activity = this;
|
TildeFriendsActivity activity = this;
|
||||||
|
|
||||||
thread = new Thread(new Runnable() {
|
Log.w("tildefriends", "Watching for changes in: " + getFilesDir().toString());
|
||||||
@Override
|
observer = make_file_observer(getFilesDir().toString(), port_file_path);
|
||||||
public void run() {
|
observer.startWatching();
|
||||||
Log.w("tildefriends", "Watching for changes in: " + getFilesDir().toString());
|
|
||||||
try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
|
|
||||||
Paths.get(getFilesDir().toString()).register(
|
|
||||||
watcher,
|
|
||||||
StandardWatchEventKinds.ENTRY_CREATE,
|
|
||||||
StandardWatchEventKinds.ENTRY_MODIFY);
|
|
||||||
while (true) {
|
|
||||||
WatchKey key = watcher.poll(100, TimeUnit.MILLISECONDS);
|
|
||||||
boolean attempt_it = true;
|
|
||||||
if (key != null)
|
|
||||||
{
|
|
||||||
attempt_it = false;
|
|
||||||
for (WatchEvent event : key.pollEvents()) {
|
|
||||||
if (event.context().toString().equals("port.txt")) {
|
|
||||||
Log.w("tildefriends", "Observed file write: " + event.context().toString());
|
|
||||||
attempt_it = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (attempt_it) {
|
|
||||||
int port = read_port(port_file_path);
|
|
||||||
if (port >= 0) {
|
|
||||||
base_url = "http://127.0.0.1:" + String.valueOf(port) + "/";
|
|
||||||
activity.runOnUiThread(() -> {
|
|
||||||
activity.hide_status();
|
|
||||||
web_view.loadUrl(base_url);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
activity.runOnUiThread(() -> {
|
|
||||||
activity.set_status("Waiting to connect...");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (key != null && !key.reset()) {
|
|
||||||
Log.w("tildefriends", "watcher is no longer valid");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (java.io.IOException e) {
|
|
||||||
Log.w("tildefriends", "IOException: " + e.toString());
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.w("tildefriends", "InterruptedException: " + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
thread.start();
|
|
||||||
|
|
||||||
set_status("Starting server...");
|
set_status("Starting server...");
|
||||||
server_thread = new Thread(new Runnable() {
|
server_thread = new Thread(new Runnable() {
|
||||||
@ -165,6 +113,8 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
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 + ")");
|
||||||
@ -390,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();
|
||||||
}
|
}
|
||||||
@ -458,4 +411,42 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
s_activity.service_connection = null;
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ public class TildeFriendsSandboxService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
|
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
|
||||||
if (code == START_CALL) {
|
if (code == START_CALL) {
|
||||||
ParcelFileDescriptor pfd = data.readParcelable(ParcelFileDescriptor.class.getClassLoader(), ParcelFileDescriptor.class);
|
ParcelFileDescriptor pfd = read_pfd(data);
|
||||||
if (pfd != null) {
|
if (pfd != null) {
|
||||||
Log.w("tildefriends", "fd is " + pfd.getFd());
|
Log.w("tildefriends", "fd is " + pfd.getFd());
|
||||||
start_thread(pfd.detachFd());
|
start_thread(pfd.detachFd());
|
||||||
@ -56,4 +56,9 @@ public class TildeFriendsSandboxService extends Service {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
static private ParcelFileDescriptor read_pfd(Parcel data) {
|
||||||
|
return data.readParcelable(ParcelFileDescriptor.class.getClassLoader());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1689,6 +1689,7 @@ void tf_httpd_register(JSContext* context)
|
|||||||
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, "/~*/*/", _httpd_endpoint_static, NULL, task);
|
tf_http_add_handler(http, "/~*/*/", _httpd_endpoint_static, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/&*.sha256/", _httpd_endpoint_static, NULL, task);
|
||||||
|
|
||||||
tf_http_add_handler(http, "/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);
|
||||||
|
238
src/ssb.c
238
src/ssb.c
@ -80,6 +80,8 @@ enum
|
|||||||
k_seed_expire_seconds = 10 * 60,
|
k_seed_expire_seconds = 10 * 60,
|
||||||
k_seed_check_interval_seconds = 5 * 60,
|
k_seed_check_interval_seconds = 5 * 60,
|
||||||
k_udp_discovery_expires_seconds = 10,
|
k_udp_discovery_expires_seconds = 10,
|
||||||
|
k_handshake_timeout_ms = 15000,
|
||||||
|
k_rpc_active_ms = 3000,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _tf_ssb_broadcast_t tf_ssb_broadcast_t;
|
typedef struct _tf_ssb_broadcast_t tf_ssb_broadcast_t;
|
||||||
@ -111,6 +113,7 @@ typedef struct _tf_ssb_request_t
|
|||||||
tf_ssb_callback_cleanup_t* cleanup;
|
tf_ssb_callback_cleanup_t* cleanup;
|
||||||
void* user_data;
|
void* user_data;
|
||||||
tf_ssb_connection_t* dependent_connection;
|
tf_ssb_connection_t* dependent_connection;
|
||||||
|
uint64_t last_active;
|
||||||
int32_t request_number;
|
int32_t request_number;
|
||||||
} tf_ssb_request_t;
|
} tf_ssb_request_t;
|
||||||
|
|
||||||
@ -130,8 +133,7 @@ typedef struct _tf_ssb_broadcast_t
|
|||||||
typedef struct _tf_ssb_rpc_callback_node_t tf_ssb_rpc_callback_node_t;
|
typedef struct _tf_ssb_rpc_callback_node_t tf_ssb_rpc_callback_node_t;
|
||||||
typedef struct _tf_ssb_rpc_callback_node_t
|
typedef struct _tf_ssb_rpc_callback_node_t
|
||||||
{
|
{
|
||||||
const char** name;
|
const char* name;
|
||||||
const char* flattened_name;
|
|
||||||
tf_ssb_rpc_callback_t* callback;
|
tf_ssb_rpc_callback_t* callback;
|
||||||
tf_ssb_callback_cleanup_t* cleanup;
|
tf_ssb_callback_cleanup_t* cleanup;
|
||||||
void* user_data;
|
void* user_data;
|
||||||
@ -211,6 +213,7 @@ typedef struct _tf_ssb_t
|
|||||||
uv_timer_t broadcast_cleanup_timer;
|
uv_timer_t broadcast_cleanup_timer;
|
||||||
uv_timer_t broadcast_timer;
|
uv_timer_t broadcast_timer;
|
||||||
uv_timer_t trace_timer;
|
uv_timer_t trace_timer;
|
||||||
|
uv_timer_t request_activity_timer;
|
||||||
uv_tcp_t server;
|
uv_tcp_t server;
|
||||||
|
|
||||||
uint8_t network_key[32];
|
uint8_t network_key[32];
|
||||||
@ -294,6 +297,7 @@ typedef struct _tf_ssb_connection_t
|
|||||||
uv_tcp_t tcp;
|
uv_tcp_t tcp;
|
||||||
uv_connect_t connect;
|
uv_connect_t connect;
|
||||||
uv_async_t async;
|
uv_async_t async;
|
||||||
|
uv_timer_t handshake_timer;
|
||||||
bool closing;
|
bool closing;
|
||||||
|
|
||||||
tf_ssb_connection_t* tunnel_connection;
|
tf_ssb_connection_t* tunnel_connection;
|
||||||
@ -359,6 +363,8 @@ typedef struct _tf_ssb_connection_t
|
|||||||
|
|
||||||
int read_back_pressure;
|
int read_back_pressure;
|
||||||
int active_write_count;
|
int active_write_count;
|
||||||
|
|
||||||
|
uint64_t last_notified_active;
|
||||||
} tf_ssb_connection_t;
|
} tf_ssb_connection_t;
|
||||||
|
|
||||||
static JSClassID _connection_class_id;
|
static JSClassID _connection_class_id;
|
||||||
@ -678,17 +684,53 @@ static bool _tf_ssb_connection_get_request_callback(tf_ssb_connection_t* connect
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _tf_ssb_request_activity_timer(uv_timer_t* timer)
|
||||||
|
{
|
||||||
|
tf_ssb_t* ssb = timer->data;
|
||||||
|
uint64_t now_ms = uv_now(ssb->loop);
|
||||||
|
bool any_still_active = false;
|
||||||
|
for (tf_ssb_connection_t* connection = ssb->connections; connection; connection = connection->next)
|
||||||
|
{
|
||||||
|
bool any_changed = false;
|
||||||
|
bool last_notified_active = (now_ms - connection->last_notified_active) < k_rpc_active_ms;
|
||||||
|
for (int i = 0; i < connection->requests_count; i++)
|
||||||
|
{
|
||||||
|
bool last_active = (now_ms - connection->requests[i].last_active) < k_rpc_active_ms;
|
||||||
|
if (last_active != last_notified_active)
|
||||||
|
{
|
||||||
|
any_changed = true;
|
||||||
|
}
|
||||||
|
if (last_active)
|
||||||
|
{
|
||||||
|
any_still_active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (any_changed)
|
||||||
|
{
|
||||||
|
_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_update, connection);
|
||||||
|
connection->last_notified_active = now_ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any_still_active)
|
||||||
|
{
|
||||||
|
uv_timer_start(&ssb->request_activity_timer, _tf_ssb_request_activity_timer, k_rpc_active_ms, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t request_number, const char* name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup,
|
void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t request_number, const char* name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup,
|
||||||
void* user_data, tf_ssb_connection_t* dependent_connection)
|
void* user_data, tf_ssb_connection_t* dependent_connection)
|
||||||
{
|
{
|
||||||
tf_ssb_request_t* existing =
|
tf_ssb_request_t* existing =
|
||||||
connection->requests_count ? bsearch(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare) : NULL;
|
connection->requests_count ? bsearch(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare) : NULL;
|
||||||
|
uint64_t now_ms = uv_now(connection->ssb->loop);
|
||||||
if (existing)
|
if (existing)
|
||||||
{
|
{
|
||||||
assert(!existing->callback);
|
assert(!existing->callback);
|
||||||
assert(!existing->cleanup);
|
assert(!existing->cleanup);
|
||||||
assert(!existing->user_data);
|
assert(!existing->user_data);
|
||||||
assert(!existing->dependent_connection);
|
assert(!existing->dependent_connection);
|
||||||
|
existing->last_active = now_ms;
|
||||||
existing->callback = callback;
|
existing->callback = callback;
|
||||||
existing->cleanup = cleanup;
|
existing->cleanup = cleanup;
|
||||||
existing->user_data = user_data;
|
existing->user_data = user_data;
|
||||||
@ -703,6 +745,7 @@ void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t requ
|
|||||||
.cleanup = cleanup,
|
.cleanup = cleanup,
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
.dependent_connection = dependent_connection,
|
.dependent_connection = dependent_connection,
|
||||||
|
.last_active = now_ms,
|
||||||
};
|
};
|
||||||
snprintf(request.name, sizeof(request.name), "%s", name);
|
snprintf(request.name, sizeof(request.name), "%s", name);
|
||||||
int index = tf_util_insert_index(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare);
|
int index = tf_util_insert_index(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare);
|
||||||
@ -713,10 +756,14 @@ void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t requ
|
|||||||
}
|
}
|
||||||
connection->requests[index] = request;
|
connection->requests[index] = request;
|
||||||
connection->requests_count++;
|
connection->requests_count++;
|
||||||
|
|
||||||
connection->ssb->request_count++;
|
connection->ssb->request_count++;
|
||||||
}
|
}
|
||||||
|
if (uv_timer_get_due_in(&connection->ssb->request_activity_timer) == 0)
|
||||||
|
{
|
||||||
|
uv_timer_start(&connection->ssb->request_activity_timer, _tf_ssb_request_activity_timer, k_rpc_active_ms, 0);
|
||||||
|
}
|
||||||
_tf_ssb_notify_connections_changed(connection->ssb, k_tf_ssb_change_update, connection);
|
_tf_ssb_notify_connections_changed(connection->ssb, k_tf_ssb_change_update, connection);
|
||||||
|
connection->last_notified_active = now_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _message_request_compare(const void* a, const void* b)
|
static int _message_request_compare(const void* a, const void* b)
|
||||||
@ -1258,6 +1305,10 @@ static void _tf_ssb_connection_verify_identity(tf_ssb_connection_t* connection,
|
|||||||
JS_SetPropertyStr(context, connection->object, "is_client", JS_TRUE);
|
JS_SetPropertyStr(context, connection->object, "is_client", JS_TRUE);
|
||||||
|
|
||||||
connection->state = k_tf_ssb_state_verified;
|
connection->state = k_tf_ssb_state_verified;
|
||||||
|
if (connection->handshake_timer.data)
|
||||||
|
{
|
||||||
|
uv_timer_stop(&connection->handshake_timer);
|
||||||
|
}
|
||||||
_tf_ssb_notify_connections_changed(connection->ssb, k_tf_ssb_change_connect, connection);
|
_tf_ssb_notify_connections_changed(connection->ssb, k_tf_ssb_change_connect, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1486,6 +1537,10 @@ static void _tf_ssb_connection_verify_client_identity(tf_ssb_connection_t* conne
|
|||||||
JS_SetPropertyStr(context, connection->object, "is_client", JS_FALSE);
|
JS_SetPropertyStr(context, connection->object, "is_client", JS_FALSE);
|
||||||
|
|
||||||
connection->state = k_tf_ssb_state_server_verified;
|
connection->state = k_tf_ssb_state_server_verified;
|
||||||
|
if (connection->handshake_timer.data)
|
||||||
|
{
|
||||||
|
uv_timer_stop(&connection->handshake_timer);
|
||||||
|
}
|
||||||
_tf_ssb_notify_connections_changed(connection->ssb, k_tf_ssb_change_connect, connection);
|
_tf_ssb_notify_connections_changed(connection->ssb, k_tf_ssb_change_connect, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1511,60 +1566,28 @@ static bool _tf_ssb_connection_recv_pop(tf_ssb_connection_t* connection, uint8_t
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _tf_ssb_name_equals(JSContext* context, JSValue object, const char** match)
|
static void _tf_ssb_name_to_string(JSContext* context, JSValue object, char* buffer, size_t size)
|
||||||
{
|
{
|
||||||
bool result = true;
|
|
||||||
JSValue name = JS_GetPropertyStr(context, object, "name");
|
JSValue name = JS_GetPropertyStr(context, object, "name");
|
||||||
|
|
||||||
if (JS_IsArray(context, name))
|
if (JS_IsArray(context, name))
|
||||||
{
|
{
|
||||||
int length = tf_util_get_length(context, name);
|
int length = tf_util_get_length(context, name);
|
||||||
|
int offset = 0;
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
if (!match[i])
|
JSValue part = JS_GetPropertyUint32(context, name, i);
|
||||||
{
|
const char* part_str = JS_ToCString(context, part);
|
||||||
result = false;
|
offset += snprintf(buffer + offset, size - offset, "%s%s", i == 0 ? "" : ".", part_str);
|
||||||
break;
|
JS_FreeCString(context, part_str);
|
||||||
}
|
JS_FreeValue(context, part);
|
||||||
|
|
||||||
JSValue element = JS_GetPropertyUint32(context, name, i);
|
|
||||||
const char* str = JS_ToCString(context, element);
|
|
||||||
if (!str || strcmp(str, match[i]) != 0)
|
|
||||||
{
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
JS_FreeCString(context, str);
|
|
||||||
JS_FreeValue(context, element);
|
|
||||||
}
|
|
||||||
if (result && match[length])
|
|
||||||
{
|
|
||||||
result = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (JS_IsString(name))
|
else if (JS_IsString(name))
|
||||||
{
|
{
|
||||||
/* Manifest is traditionally sent as not an array for some reason. */
|
const char* part_str = JS_ToCString(context, name);
|
||||||
const char* str = JS_ToCString(context, name);
|
snprintf(buffer, size, "%s", part_str);
|
||||||
result = str && match[0] && strcmp(str, match[0]) == 0 && !match[1];
|
JS_FreeCString(context, part_str);
|
||||||
JS_FreeCString(context, str);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_FreeValue(context, name);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _tf_ssb_name_to_string(JSContext* context, JSValue object, char* buffer, size_t size)
|
|
||||||
{
|
|
||||||
JSValue name = JS_GetPropertyStr(context, object, "name");
|
|
||||||
JSValue json_val = JS_JSONStringify(context, name, JS_NULL, JS_NewInt32(context, 2));
|
|
||||||
const char* value = JS_ToCString(context, json_val);
|
|
||||||
snprintf(buffer, size, "%s", value);
|
|
||||||
JS_FreeCString(context, value);
|
|
||||||
JS_FreeValue(context, json_val);
|
|
||||||
JS_FreeValue(context, name);
|
JS_FreeValue(context, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1614,35 +1637,14 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
|||||||
else if (JS_IsObject(val))
|
else if (JS_IsObject(val))
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
char namebuf[256] = "";
|
char name[256] = "";
|
||||||
JSValue name = JS_GetPropertyStr(context, val, "name");
|
_tf_ssb_name_to_string(context, val, name, sizeof(name));
|
||||||
if (JS_IsArray(context, name))
|
|
||||||
{
|
|
||||||
int length = tf_util_get_length(context, name);
|
|
||||||
int offset = 0;
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
JSValue part = JS_GetPropertyUint32(context, name, i);
|
|
||||||
const char* part_str = JS_ToCString(context, part);
|
|
||||||
offset += snprintf(namebuf + offset, sizeof(namebuf) - offset, "%s%s", i == 0 ? "" : ".", part_str);
|
|
||||||
JS_FreeCString(context, part_str);
|
|
||||||
JS_FreeValue(context, part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (JS_IsString(name))
|
|
||||||
{
|
|
||||||
const char* part_str = JS_ToCString(context, name);
|
|
||||||
snprintf(namebuf, sizeof(namebuf), "%s", part_str);
|
|
||||||
JS_FreeCString(context, part_str);
|
|
||||||
}
|
|
||||||
JS_FreeValue(context, name);
|
|
||||||
|
|
||||||
for (tf_ssb_rpc_callback_node_t* it = connection->ssb->rpc; it; it = it->next)
|
for (tf_ssb_rpc_callback_node_t* it = connection->ssb->rpc; it; it = it->next)
|
||||||
{
|
{
|
||||||
if (_tf_ssb_name_equals(context, val, it->name))
|
if (strcmp(name, it->name) == 0)
|
||||||
{
|
{
|
||||||
tf_ssb_connection_add_request(connection, -request_number, namebuf, NULL, NULL, NULL, NULL);
|
tf_ssb_connection_add_request(connection, -request_number, name, NULL, NULL, NULL, NULL);
|
||||||
tf_trace_begin(connection->ssb->trace, it->flattened_name);
|
tf_trace_begin(connection->ssb->trace, it->name);
|
||||||
PRE_CALLBACK(connection->ssb, it->callback);
|
PRE_CALLBACK(connection->ssb, it->callback);
|
||||||
it->callback(connection, flags, request_number, val, message, size, it->user_data);
|
it->callback(connection, flags, request_number, val, message, size, it->user_data);
|
||||||
POST_CALLBACK(connection->ssb, it->callback);
|
POST_CALLBACK(connection->ssb, it->callback);
|
||||||
@ -1651,12 +1653,10 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found && !_tf_ssb_name_equals(context, val, (const char*[]) { "Error", NULL }))
|
if (!found && strcmp(name, "Error") != 0)
|
||||||
{
|
{
|
||||||
tf_ssb_connection_add_request(connection, -request_number, namebuf, NULL, NULL, NULL, NULL);
|
tf_ssb_connection_add_request(connection, -request_number, name, NULL, NULL, NULL, NULL);
|
||||||
char buffer[256];
|
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, name);
|
||||||
_tf_ssb_name_to_string(context, val, buffer, sizeof(buffer));
|
|
||||||
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, buffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1931,8 +1931,13 @@ static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const ch
|
|||||||
{
|
{
|
||||||
uv_close((uv_handle_t*)&connection->tcp, _tf_ssb_connection_on_close);
|
uv_close((uv_handle_t*)&connection->tcp, _tf_ssb_connection_on_close);
|
||||||
}
|
}
|
||||||
|
if (connection->handshake_timer.data && !uv_is_closing((uv_handle_t*)&connection->handshake_timer))
|
||||||
|
{
|
||||||
|
uv_close((uv_handle_t*)&connection->handshake_timer, _tf_ssb_connection_on_close);
|
||||||
|
}
|
||||||
|
|
||||||
if (JS_IsUndefined(connection->object) && !connection->async.data && !connection->tcp.data && !connection->connect.data && connection->ref_count == 0)
|
if (JS_IsUndefined(connection->object) && !connection->async.data && !connection->tcp.data && !connection->connect.data && !connection->handshake_timer.data &&
|
||||||
|
connection->ref_count == 0)
|
||||||
{
|
{
|
||||||
tf_free(connection->message_requests);
|
tf_free(connection->message_requests);
|
||||||
connection->message_requests = NULL;
|
connection->message_requests = NULL;
|
||||||
@ -1956,7 +1961,7 @@ static void _tf_ssb_connection_on_close(uv_handle_t* handle)
|
|||||||
{
|
{
|
||||||
tf_ssb_connection_t* connection = handle->data;
|
tf_ssb_connection_t* connection = handle->data;
|
||||||
handle->data = NULL;
|
handle->data = NULL;
|
||||||
if (connection)
|
if (connection && connection->closing)
|
||||||
{
|
{
|
||||||
_tf_ssb_connection_destroy(connection, "handle closed");
|
_tf_ssb_connection_destroy(connection, "handle closed");
|
||||||
}
|
}
|
||||||
@ -2257,6 +2262,11 @@ tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, const char* db_path
|
|||||||
uv_timer_start(&ssb->trace_timer, _tf_ssb_trace_timer, 100, 100);
|
uv_timer_start(&ssb->trace_timer, _tf_ssb_trace_timer, 100, 100);
|
||||||
uv_unref((uv_handle_t*)&ssb->trace_timer);
|
uv_unref((uv_handle_t*)&ssb->trace_timer);
|
||||||
|
|
||||||
|
ssb->request_activity_timer.data = ssb;
|
||||||
|
uv_timer_init(ssb->loop, &ssb->request_activity_timer);
|
||||||
|
uv_timer_start(&ssb->request_activity_timer, _tf_ssb_request_activity_timer, k_rpc_active_ms, 0);
|
||||||
|
uv_unref((uv_handle_t*)&ssb->request_activity_timer);
|
||||||
|
|
||||||
if (!_tf_ssb_load_keys(ssb))
|
if (!_tf_ssb_load_keys(ssb))
|
||||||
{
|
{
|
||||||
tf_printf("Generating a new keypair.\n");
|
tf_printf("Generating a new keypair.\n");
|
||||||
@ -2459,6 +2469,11 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
|||||||
uv_close((uv_handle_t*)&ssb->trace_timer, _tf_ssb_on_handle_close);
|
uv_close((uv_handle_t*)&ssb->trace_timer, _tf_ssb_on_handle_close);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ssb->request_activity_timer.data && !uv_is_closing((uv_handle_t*)&ssb->request_activity_timer))
|
||||||
|
{
|
||||||
|
uv_close((uv_handle_t*)&ssb->request_activity_timer, _tf_ssb_on_handle_close);
|
||||||
|
}
|
||||||
|
|
||||||
if (ssb->server.data && !uv_is_closing((uv_handle_t*)&ssb->server))
|
if (ssb->server.data && !uv_is_closing((uv_handle_t*)&ssb->server))
|
||||||
{
|
{
|
||||||
uv_close((uv_handle_t*)&ssb->server, _tf_ssb_on_handle_close);
|
uv_close((uv_handle_t*)&ssb->server, _tf_ssb_on_handle_close);
|
||||||
@ -2475,7 +2490,7 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
|||||||
tf_printf("Waiting for closes.\n");
|
tf_printf("Waiting for closes.\n");
|
||||||
|
|
||||||
while (ssb->broadcast_listener.data || ssb->broadcast_sender.data || ssb->broadcast_timer.data || ssb->broadcast_cleanup_timer.data || ssb->trace_timer.data ||
|
while (ssb->broadcast_listener.data || ssb->broadcast_sender.data || ssb->broadcast_timer.data || ssb->broadcast_cleanup_timer.data || ssb->trace_timer.data ||
|
||||||
ssb->server.data || ssb->ref_count)
|
ssb->server.data || ssb->ref_count || ssb->request_activity_timer.data)
|
||||||
{
|
{
|
||||||
uv_run(ssb->loop, UV_RUN_ONCE);
|
uv_run(ssb->loop, UV_RUN_ONCE);
|
||||||
}
|
}
|
||||||
@ -2643,6 +2658,15 @@ static void _tf_ssb_connection_process_message_async(uv_async_t* async)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _tf_ssb_connection_handshake_timer_callback(uv_timer_t* timer)
|
||||||
|
{
|
||||||
|
tf_ssb_connection_t* connection = timer->data;
|
||||||
|
if (connection && connection->state != k_tf_ssb_state_verified && connection->state != k_tf_ssb_state_server_verified)
|
||||||
|
{
|
||||||
|
_tf_ssb_connection_destroy(connection, "handshake timeout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tf_ssb_connection_t* tf_ssb_connection_create(tf_ssb_t* ssb, const char* host, const struct sockaddr_in* addr, const uint8_t* public_key)
|
tf_ssb_connection_t* tf_ssb_connection_create(tf_ssb_t* ssb, const char* host, const struct sockaddr_in* addr, const uint8_t* public_key)
|
||||||
{
|
{
|
||||||
for (tf_ssb_connection_t* connection = ssb->connections; connection; connection = connection->next)
|
for (tf_ssb_connection_t* connection = ssb->connections; connection; connection = connection->next)
|
||||||
@ -2677,6 +2701,10 @@ tf_ssb_connection_t* tf_ssb_connection_create(tf_ssb_t* ssb, const char* host, c
|
|||||||
connection->async.data = connection;
|
connection->async.data = connection;
|
||||||
uv_async_init(ssb->loop, &connection->async, _tf_ssb_connection_process_message_async);
|
uv_async_init(ssb->loop, &connection->async, _tf_ssb_connection_process_message_async);
|
||||||
|
|
||||||
|
connection->handshake_timer.data = connection;
|
||||||
|
uv_timer_init(ssb->loop, &connection->handshake_timer);
|
||||||
|
uv_timer_start(&connection->handshake_timer, _tf_ssb_connection_handshake_timer_callback, k_handshake_timeout_ms, 0);
|
||||||
|
|
||||||
connection->object = JS_NewObjectClass(ssb->context, _connection_class_id);
|
connection->object = JS_NewObjectClass(ssb->context, _connection_class_id);
|
||||||
JS_SetOpaque(connection->object, connection);
|
JS_SetOpaque(connection->object, connection);
|
||||||
char public_key_str[k_id_base64_len] = { 0 };
|
char public_key_str[k_id_base64_len] = { 0 };
|
||||||
@ -2712,6 +2740,7 @@ static void _tf_ssb_connection_tunnel_callback(
|
|||||||
tf_ssb_connection_t* tunnel = user_data;
|
tf_ssb_connection_t* tunnel = user_data;
|
||||||
if (flags & k_ssb_rpc_flag_end_error)
|
if (flags & k_ssb_rpc_flag_end_error)
|
||||||
{
|
{
|
||||||
|
tf_ssb_connection_remove_request(connection, -request_number);
|
||||||
tf_ssb_connection_rpc_send(connection, flags, -request_number, NULL, (const uint8_t*)"false", strlen("false"), NULL, NULL, NULL);
|
tf_ssb_connection_rpc_send(connection, flags, -request_number, NULL, (const uint8_t*)"false", strlen("false"), NULL, NULL, NULL);
|
||||||
tf_ssb_connection_close(tunnel);
|
tf_ssb_connection_close(tunnel);
|
||||||
}
|
}
|
||||||
@ -2737,6 +2766,10 @@ tf_ssb_connection_t* tf_ssb_connection_tunnel_create(tf_ssb_t* ssb, const char*
|
|||||||
tunnel->async.data = tunnel;
|
tunnel->async.data = tunnel;
|
||||||
uv_async_init(ssb->loop, &tunnel->async, _tf_ssb_connection_process_message_async);
|
uv_async_init(ssb->loop, &tunnel->async, _tf_ssb_connection_process_message_async);
|
||||||
|
|
||||||
|
tunnel->handshake_timer.data = tunnel;
|
||||||
|
uv_timer_init(ssb->loop, &tunnel->handshake_timer);
|
||||||
|
uv_timer_start(&tunnel->handshake_timer, _tf_ssb_connection_handshake_timer_callback, k_handshake_timeout_ms, 0);
|
||||||
|
|
||||||
tunnel->object = JS_NewObjectClass(ssb->context, _connection_class_id);
|
tunnel->object = JS_NewObjectClass(ssb->context, _connection_class_id);
|
||||||
JS_SetOpaque(tunnel->object, tunnel);
|
JS_SetOpaque(tunnel->object, tunnel);
|
||||||
JS_SetPropertyStr(context, tunnel->object, "id", JS_NewString(context, target_id));
|
JS_SetPropertyStr(context, tunnel->object, "id", JS_NewString(context, target_id));
|
||||||
@ -2859,6 +2892,10 @@ static void _tf_ssb_on_connection(uv_stream_t* stream, int status)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connection->handshake_timer.data = connection;
|
||||||
|
uv_timer_init(ssb->loop, &connection->handshake_timer);
|
||||||
|
uv_timer_start(&connection->handshake_timer, _tf_ssb_connection_handshake_timer_callback, k_handshake_timeout_ms, 0);
|
||||||
|
|
||||||
struct sockaddr_storage addr = { 0 };
|
struct sockaddr_storage addr = { 0 };
|
||||||
int size = sizeof(addr);
|
int size = sizeof(addr);
|
||||||
if (uv_tcp_getpeername(&connection->tcp, (struct sockaddr*)&addr, &size) == 0)
|
if (uv_tcp_getpeername(&connection->tcp, (struct sockaddr*)&addr, &size) == 0)
|
||||||
@ -2870,10 +2907,10 @@ static void _tf_ssb_on_connection(uv_stream_t* stream, int status)
|
|||||||
connection->next = ssb->connections;
|
connection->next = ssb->connections;
|
||||||
ssb->connections = connection;
|
ssb->connections = connection;
|
||||||
ssb->connections_count++;
|
ssb->connections_count++;
|
||||||
_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_create, connection);
|
|
||||||
|
|
||||||
connection->state = k_tf_ssb_state_server_wait_hello;
|
connection->state = k_tf_ssb_state_server_wait_hello;
|
||||||
_tf_ssb_connection_read_start(connection);
|
_tf_ssb_connection_read_start(connection);
|
||||||
|
_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_create, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_send_broadcast(tf_ssb_t* ssb, struct sockaddr_in* address, struct sockaddr_in* netmask)
|
static void _tf_ssb_send_broadcast(tf_ssb_t* ssb, struct sockaddr_in* address, struct sockaddr_in* netmask)
|
||||||
@ -3443,47 +3480,18 @@ void tf_ssb_remove_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_connection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_add_rpc_callback(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
void tf_ssb_add_rpc_callback(tf_ssb_t* ssb, const char* name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
||||||
{
|
{
|
||||||
size_t name_len = 0;
|
size_t name_len = strlen(name);
|
||||||
int name_count = 0;
|
tf_ssb_rpc_callback_node_t* node = tf_malloc(sizeof(tf_ssb_rpc_callback_node_t) + name_len + 1);
|
||||||
for (int i = 0; name[i]; i++)
|
|
||||||
{
|
|
||||||
name_count++;
|
|
||||||
name_len += strlen(name[i]) + 1;
|
|
||||||
}
|
|
||||||
tf_ssb_rpc_callback_node_t* node = tf_malloc(sizeof(tf_ssb_rpc_callback_node_t) + (name_count + 1) * sizeof(const char*) + name_len + name_len + 3);
|
|
||||||
*node = (tf_ssb_rpc_callback_node_t) {
|
*node = (tf_ssb_rpc_callback_node_t) {
|
||||||
.name = (const char**)(node + 1),
|
.name = (const char*)(node + 1),
|
||||||
.flattened_name = (const char*)(node + 1) + (name_count + 1) * sizeof(const char*) + name_len,
|
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.cleanup = cleanup,
|
.cleanup = cleanup,
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
.next = ssb->rpc,
|
.next = ssb->rpc,
|
||||||
};
|
};
|
||||||
char* p = (char*)(node + 1) + (name_count + 1) * sizeof(const char*);
|
memcpy((char*)node->name, name, name_len + 1);
|
||||||
for (int i = 0; i < name_count; i++)
|
|
||||||
{
|
|
||||||
size_t len = strlen(name[i]);
|
|
||||||
memcpy(p, name[i], len + 1);
|
|
||||||
node->name[i] = p;
|
|
||||||
p += len + 1;
|
|
||||||
}
|
|
||||||
char* flattened_name = (char*)node->flattened_name;
|
|
||||||
for (int i = 0; i < name_count; i++)
|
|
||||||
{
|
|
||||||
size_t length = strlen(name[i]);
|
|
||||||
memcpy(flattened_name, name[i], length);
|
|
||||||
flattened_name += length;
|
|
||||||
if (i != name_count - 1)
|
|
||||||
{
|
|
||||||
*flattened_name++ = '.';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*flattened_name++ = '(';
|
|
||||||
*flattened_name++ = ')';
|
|
||||||
*flattened_name++ = '\0';
|
|
||||||
node->name[name_count] = NULL;
|
|
||||||
ssb->rpc = node;
|
ssb->rpc = node;
|
||||||
ssb->rpc_count++;
|
ssb->rpc_count++;
|
||||||
}
|
}
|
||||||
@ -4229,11 +4237,13 @@ JSValue tf_ssb_connection_requests_to_object(tf_ssb_connection_t* connection)
|
|||||||
{
|
{
|
||||||
JSContext* context = connection->ssb->context;
|
JSContext* context = connection->ssb->context;
|
||||||
JSValue object = JS_NewArray(context);
|
JSValue object = JS_NewArray(context);
|
||||||
|
uint64_t now_ms = uv_now(connection->ssb->loop);
|
||||||
for (int i = 0; i < connection->requests_count; i++)
|
for (int i = 0; i < connection->requests_count; i++)
|
||||||
{
|
{
|
||||||
JSValue request = JS_NewObject(context);
|
JSValue request = JS_NewObject(context);
|
||||||
JS_SetPropertyStr(context, request, "name", JS_NewString(context, connection->requests[i].name));
|
JS_SetPropertyStr(context, request, "name", JS_NewString(context, connection->requests[i].name));
|
||||||
JS_SetPropertyStr(context, request, "request_number", JS_NewInt32(context, connection->requests[i].request_number));
|
JS_SetPropertyStr(context, request, "request_number", JS_NewInt32(context, connection->requests[i].request_number));
|
||||||
|
JS_SetPropertyStr(context, request, "active", JS_NewBool(context, (now_ms - connection->requests[i].last_active) < k_rpc_active_ms));
|
||||||
JS_SetPropertyUint32(context, object, i, request);
|
JS_SetPropertyUint32(context, object, i, request);
|
||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
|
@ -21,6 +21,11 @@ typedef struct _tf_ssb_connections_t
|
|||||||
|
|
||||||
static void _tf_ssb_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection, void* user_data)
|
static void _tf_ssb_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection, void* user_data)
|
||||||
{
|
{
|
||||||
|
if (!connection)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tf_ssb_connections_t* connections = user_data;
|
tf_ssb_connections_t* connections = user_data;
|
||||||
switch (change)
|
switch (change)
|
||||||
{
|
{
|
||||||
|
22
src/ssb.db.c
22
src/ssb.db.c
@ -133,6 +133,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
|||||||
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_sequence_index ON messages (author, sequence)");
|
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_sequence_index ON messages (author, sequence)");
|
||||||
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_timestamp_index ON messages (author, timestamp)");
|
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_timestamp_index ON messages (author, timestamp)");
|
||||||
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_timestamp_index ON messages (timestamp)");
|
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_timestamp_index ON messages (timestamp)");
|
||||||
|
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_type_timestamp_index ON messages (content ->> 'type', timestamp)");
|
||||||
_tf_ssb_db_exec(db,
|
_tf_ssb_db_exec(db,
|
||||||
"CREATE TABLE IF NOT EXISTS blobs ("
|
"CREATE TABLE IF NOT EXISTS blobs ("
|
||||||
" id TEXT PRIMARY KEY,"
|
" id TEXT PRIMARY KEY,"
|
||||||
@ -1945,3 +1946,24 @@ bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id)
|
|||||||
}
|
}
|
||||||
return verified;
|
return verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tf_ssb_db_user_has_permission(tf_ssb_t* ssb, const char* id, const char* permission)
|
||||||
|
{
|
||||||
|
bool has_permission = false;
|
||||||
|
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||||
|
sqlite3_stmt* statement = NULL;
|
||||||
|
if (sqlite3_prepare(db,
|
||||||
|
"SELECT COUNT(*) FROM properties, json_each(properties.value -> 'permissions' -> ?) AS permission WHERE properties.id = 'core' AND properties.key = 'settings' AND "
|
||||||
|
"permission.value = ?",
|
||||||
|
-1, &statement, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, permission, -1, NULL) == SQLITE_OK &&
|
||||||
|
sqlite3_step(statement) == SQLITE_ROW)
|
||||||
|
{
|
||||||
|
has_permission = sqlite3_column_int64(statement, 0) > 0;
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
}
|
||||||
|
tf_ssb_release_db_reader(ssb, db);
|
||||||
|
return has_permission;
|
||||||
|
}
|
||||||
|
@ -416,6 +416,15 @@ void tf_ssb_db_resolve_index_async(tf_ssb_t* ssb, const char* host, void (*callb
|
|||||||
*/
|
*/
|
||||||
bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id);
|
bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Check if a user has a specific permission.
|
||||||
|
** @param ssb The SSB instance.
|
||||||
|
** @param id The user ID.
|
||||||
|
** @param permission The name of the permission.
|
||||||
|
** @return true If the user has the requested permission.
|
||||||
|
*/
|
||||||
|
bool tf_ssb_db_user_has_permission(tf_ssb_t* ssb, const char* id, const char* permission);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** An SQLite authorizer callback. See https://www.sqlite.org/c3ref/set_authorizer.html for use.
|
** An SQLite authorizer callback. See https://www.sqlite.org/c3ref/set_authorizer.html for use.
|
||||||
** @param user_data User data registered with the authorizer.
|
** @param user_data User data registered with the authorizer.
|
||||||
|
@ -69,7 +69,7 @@ static void _tf_ssb_export_scandir(uv_fs_t* req)
|
|||||||
int r = uv_fs_unlink(tf_ssb_get_loop(export->ssb), &req, path, NULL);
|
int r = uv_fs_unlink(tf_ssb_get_loop(export->ssb), &req, path, NULL);
|
||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
tf_printf("Failed to unlink %s: %s.", path, uv_strerror(r));
|
tf_printf("Failed to unlink %s: %s.\n", path, uv_strerror(r));
|
||||||
}
|
}
|
||||||
uv_fs_req_cleanup(&req);
|
uv_fs_req_cleanup(&req);
|
||||||
tf_free(path);
|
tf_free(path);
|
||||||
@ -199,7 +199,7 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
|
|||||||
int r = uv_fs_scandir(tf_ssb_get_loop(ssb), &export.req, file_path, 0, _tf_ssb_export_scandir);
|
int r = uv_fs_scandir(tf_ssb_get_loop(ssb), &export.req, file_path, 0, _tf_ssb_export_scandir);
|
||||||
if (r)
|
if (r)
|
||||||
{
|
{
|
||||||
tf_printf("Failed to scan directory %s: %s.", file_path, uv_strerror(r));
|
tf_printf("Failed to scan directory %s: %s.\n", file_path, uv_strerror(r));
|
||||||
}
|
}
|
||||||
while (!export.done)
|
while (!export.done)
|
||||||
{
|
{
|
||||||
|
@ -676,12 +676,12 @@ typedef void(tf_ssb_rpc_callback_t)(tf_ssb_connection_t* connection, uint8_t fla
|
|||||||
/**
|
/**
|
||||||
** Register a MUXRPC callback by name.
|
** Register a MUXRPC callback by name.
|
||||||
** @param ssb The SSB instance.
|
** @param ssb The SSB instance.
|
||||||
** @param name The NULL-terminated name.
|
** @param name The RPC name as a .-separated string.
|
||||||
** @param callback The callback.
|
** @param callback The callback.
|
||||||
** @param cleanup A function to be called when the callback is removed.
|
** @param cleanup A function to be called when the callback is removed.
|
||||||
** @param user_data User data to pass to the callback.
|
** @param user_data User data to pass to the callback.
|
||||||
*/
|
*/
|
||||||
void tf_ssb_add_rpc_callback(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
void tf_ssb_add_rpc_callback(tf_ssb_t* ssb, const char* name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Remove a MUXRPC callback.
|
** Remove a MUXRPC callback.
|
||||||
|
@ -155,7 +155,7 @@ static void _tf_ssb_import_recursive_add_files(tf_ssb_t* ssb, uv_loop_t* loop, J
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tf_printf("Failed to scan directory %s: %s.", path, uv_strerror(r));
|
tf_printf("Failed to scan directory %s: %s.\n", path, uv_strerror(r));
|
||||||
}
|
}
|
||||||
uv_fs_req_cleanup(&req);
|
uv_fs_req_cleanup(&req);
|
||||||
}
|
}
|
||||||
@ -260,7 +260,7 @@ void tf_ssb_import(tf_ssb_t* ssb, const char* user, const char* path)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tf_printf("Failed to scan directory %s: %s.", path, uv_strerror(r));
|
tf_printf("Failed to scan directory %s: %s.\n", path, uv_strerror(r));
|
||||||
}
|
}
|
||||||
uv_fs_req_cleanup(&req);
|
uv_fs_req_cleanup(&req);
|
||||||
}
|
}
|
||||||
|
31
src/ssb.js.c
31
src/ssb.js.c
@ -381,6 +381,14 @@ static void _tf_ssb_getIdentities_visit(const char* identity, void* user_data)
|
|||||||
static void _tf_ssb_get_identities_work(tf_ssb_t* ssb, void* user_data)
|
static void _tf_ssb_get_identities_work(tf_ssb_t* ssb, void* user_data)
|
||||||
{
|
{
|
||||||
identities_visit_t* work = user_data;
|
identities_visit_t* work = user_data;
|
||||||
|
if (tf_ssb_db_user_has_permission(ssb, work->user, "administration"))
|
||||||
|
{
|
||||||
|
char id[k_id_base64_len] = "";
|
||||||
|
if (tf_ssb_whoami(ssb, id, sizeof(id)))
|
||||||
|
{
|
||||||
|
_tf_ssb_getIdentities_visit(*id == '@' ? id + 1 : id, work);
|
||||||
|
}
|
||||||
|
}
|
||||||
tf_ssb_db_identity_visit(ssb, work->user, _tf_ssb_getIdentities_visit, user_data);
|
tf_ssb_db_identity_visit(ssb, work->user, _tf_ssb_getIdentities_visit, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,6 +453,10 @@ static void _tf_ssb_get_private_key_work(tf_ssb_t* ssb, void* user_data)
|
|||||||
{
|
{
|
||||||
get_private_key_t* work = user_data;
|
get_private_key_t* work = user_data;
|
||||||
work->got_private_key = tf_ssb_db_identity_get_private_key(ssb, work->user, work->id, work->private_key, sizeof(work->private_key));
|
work->got_private_key = tf_ssb_db_identity_get_private_key(ssb, work->user, work->id, work->private_key, sizeof(work->private_key));
|
||||||
|
if (!work->got_private_key && tf_ssb_db_user_has_permission(ssb, work->user, "administration"))
|
||||||
|
{
|
||||||
|
work->got_private_key = tf_ssb_db_identity_get_private_key(ssb, ":admin", work->id, work->private_key, sizeof(work->private_key));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_get_private_key_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
static void _tf_ssb_get_private_key_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||||
@ -625,6 +637,14 @@ static void _tf_ssb_getIdentityInfo_visit(const char* identity, void* data)
|
|||||||
static void _tf_ssb_getIdentityInfo_work(tf_ssb_t* ssb, void* user_data)
|
static void _tf_ssb_getIdentityInfo_work(tf_ssb_t* ssb, void* user_data)
|
||||||
{
|
{
|
||||||
identity_info_work_t* request = user_data;
|
identity_info_work_t* request = user_data;
|
||||||
|
char id[k_id_base64_len] = "";
|
||||||
|
if (tf_ssb_db_user_has_permission(ssb, request->name, "administration"))
|
||||||
|
{
|
||||||
|
if (tf_ssb_whoami(ssb, id, sizeof(id)))
|
||||||
|
{
|
||||||
|
_tf_ssb_getIdentityInfo_visit(*id == '@' ? id + 1 : id, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
tf_ssb_db_identity_visit(ssb, request->name, _tf_ssb_getIdentityInfo_visit, request);
|
tf_ssb_db_identity_visit(ssb, request->name, _tf_ssb_getIdentityInfo_visit, request);
|
||||||
|
|
||||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||||
@ -637,12 +657,15 @@ static void _tf_ssb_getIdentityInfo_work(tf_ssb_t* ssb, void* user_data)
|
|||||||
" messages.content ->> 'name' AS name "
|
" messages.content ->> 'name' AS name "
|
||||||
" FROM messages "
|
" FROM messages "
|
||||||
" JOIN identities ON messages.author = ('@' || identities.public_key) "
|
" JOIN identities ON messages.author = ('@' || identities.public_key) "
|
||||||
" WHERE identities.user = ? AND json_extract(messages.content, '$.type') = 'about' AND content ->> 'about' = messages.author AND name IS NOT NULL) "
|
" WHERE "
|
||||||
|
" (identities.user = ? OR identities.public_key = ?) AND "
|
||||||
|
" json_extract(messages.content, '$.type') = 'about' AND "
|
||||||
|
" content ->> 'about' = messages.author AND name IS NOT NULL) "
|
||||||
"WHERE author_rank = 1 ",
|
"WHERE author_rank = 1 ",
|
||||||
-1, &statement, NULL);
|
-1, &statement, NULL);
|
||||||
if (request->result == SQLITE_OK)
|
if (request->result == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, request->name, -1, NULL) == SQLITE_OK)
|
if (sqlite3_bind_text(statement, 1, request->name, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, *id == '@' ? id + 1 : id, -1, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
int r = SQLITE_OK;
|
int r = SQLITE_OK;
|
||||||
while ((r = sqlite3_step(statement)) == SQLITE_ROW)
|
while ((r = sqlite3_step(statement)) == SQLITE_ROW)
|
||||||
@ -777,6 +800,10 @@ static void _tf_ssb_append_message_with_identity_get_key_work(tf_ssb_t* ssb, voi
|
|||||||
{
|
{
|
||||||
append_message_t* work = user_data;
|
append_message_t* work = user_data;
|
||||||
work->got_private_key = tf_ssb_db_identity_get_private_key(ssb, work->user, work->id, work->private_key, sizeof(work->private_key));
|
work->got_private_key = tf_ssb_db_identity_get_private_key(ssb, work->user, work->id, work->private_key, sizeof(work->private_key));
|
||||||
|
if (!work->got_private_key && tf_ssb_db_user_has_permission(ssb, work->user, "administration"))
|
||||||
|
{
|
||||||
|
work->got_private_key = tf_ssb_db_identity_get_private_key(ssb, ":admin", work->id, work->private_key, sizeof(work->private_key));
|
||||||
|
}
|
||||||
tf_ssb_db_get_latest_message_by_author(ssb, work->id, &work->previous_sequence, work->previous_id, sizeof(work->previous_id));
|
tf_ssb_db_get_latest_message_by_author(ssb, work->id, &work->previous_sequence, work->previous_id, sizeof(work->previous_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,6 +106,7 @@ static void _tf_ssb_rpc_blobs_get(tf_ssb_connection_t* connection, uint8_t flags
|
|||||||
{
|
{
|
||||||
if (flags & k_ssb_rpc_flag_end_error)
|
if (flags & k_ssb_rpc_flag_end_error)
|
||||||
{
|
{
|
||||||
|
tf_ssb_connection_remove_request(connection, -request_number);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
||||||
@ -255,19 +256,22 @@ static void _tf_ssb_request_blob_wants_work(tf_ssb_connection_t* connection, voi
|
|||||||
static void _tf_ssb_request_blob_wants_after_work(tf_ssb_connection_t* connection, int result, void* user_data)
|
static void _tf_ssb_request_blob_wants_after_work(tf_ssb_connection_t* connection, int result, void* user_data)
|
||||||
{
|
{
|
||||||
blob_wants_work_t* work = user_data;
|
blob_wants_work_t* work = user_data;
|
||||||
JSContext* context = tf_ssb_connection_get_context(connection);
|
if (!tf_ssb_is_shutting_down(tf_ssb_connection_get_ssb(connection)))
|
||||||
tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection);
|
|
||||||
for (int i = 0; i < work->out_id_count; i++)
|
|
||||||
{
|
{
|
||||||
JSValue message = JS_NewObject(context);
|
JSContext* context = tf_ssb_connection_get_context(connection);
|
||||||
JS_SetPropertyStr(context, message, work->out_id[i], JS_NewInt32(context, -1));
|
tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection);
|
||||||
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream, -blob_wants->request_number, NULL, message, NULL, NULL, NULL);
|
for (int i = 0; i < work->out_id_count; i++)
|
||||||
JS_FreeValue(context, message);
|
{
|
||||||
blob_wants->wants_sent++;
|
JSValue message = JS_NewObject(context);
|
||||||
}
|
JS_SetPropertyStr(context, message, work->out_id[i], JS_NewInt32(context, -1));
|
||||||
if (work->out_id_count)
|
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream, -blob_wants->request_number, NULL, message, NULL, NULL, NULL);
|
||||||
{
|
JS_FreeValue(context, message);
|
||||||
snprintf(blob_wants->last_id, sizeof(blob_wants->last_id), "%s", work->out_id[work->out_id_count - 1]);
|
blob_wants->wants_sent++;
|
||||||
|
}
|
||||||
|
if (work->out_id_count)
|
||||||
|
{
|
||||||
|
snprintf(blob_wants->last_id, sizeof(blob_wants->last_id), "%s", work->out_id[work->out_id_count - 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tf_free(work);
|
tf_free(work);
|
||||||
}
|
}
|
||||||
@ -1511,15 +1515,15 @@ static void _tf_ssb_rpc_peers_exchange(tf_ssb_connection_t* connection, uint8_t
|
|||||||
void tf_ssb_rpc_register(tf_ssb_t* ssb)
|
void tf_ssb_rpc_register(tf_ssb_t* ssb)
|
||||||
{
|
{
|
||||||
tf_ssb_add_connections_changed_callback(ssb, _tf_ssb_rpc_connections_changed_callback, NULL, NULL);
|
tf_ssb_add_connections_changed_callback(ssb, _tf_ssb_rpc_connections_changed_callback, NULL, NULL);
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "gossip", "ping", NULL }, _tf_ssb_rpc_gossip_ping, NULL, NULL); /* DUPLEX */
|
tf_ssb_add_rpc_callback(ssb, "gossip.ping", _tf_ssb_rpc_gossip_ping, NULL, NULL); /* DUPLEX */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "blobs", "get", NULL }, _tf_ssb_rpc_blobs_get, NULL, NULL); /* SOURCE */
|
tf_ssb_add_rpc_callback(ssb, "blobs.get", _tf_ssb_rpc_blobs_get, NULL, NULL); /* SOURCE */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "blobs", "has", NULL }, _tf_ssb_rpc_blobs_has, NULL, NULL); /* ASYNC */
|
tf_ssb_add_rpc_callback(ssb, "blobs.has", _tf_ssb_rpc_blobs_has, NULL, NULL); /* ASYNC */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "blobs", "createWants", NULL }, _tf_ssb_rpc_blobs_createWants, NULL, NULL); /* SOURCE */
|
tf_ssb_add_rpc_callback(ssb, "blobs.createWants", _tf_ssb_rpc_blobs_createWants, NULL, NULL); /* SOURCE */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "tunnel", "connect", NULL }, _tf_ssb_rpc_tunnel_connect, NULL, NULL); /* DUPLEX */
|
tf_ssb_add_rpc_callback(ssb, "tunnel.connect", _tf_ssb_rpc_tunnel_connect, NULL, NULL); /* DUPLEX */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "tunnel", "isRoom", NULL }, _tf_ssb_rpc_room_meta, NULL, NULL); /* FAKE-ASYNC */
|
tf_ssb_add_rpc_callback(ssb, "tunnel.isRoom", _tf_ssb_rpc_room_meta, NULL, NULL); /* FAKE-ASYNC */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "room", "metadata", NULL }, _tf_ssb_rpc_room_meta, NULL, NULL); /* ASYNC */
|
tf_ssb_add_rpc_callback(ssb, "room.metadata", _tf_ssb_rpc_room_meta, NULL, NULL); /* ASYNC */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "room", "attendants", NULL }, _tf_ssb_rpc_room_attendants, NULL, NULL); /* SOURCE */
|
tf_ssb_add_rpc_callback(ssb, "room.attendants", _tf_ssb_rpc_room_attendants, NULL, NULL); /* SOURCE */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "createHistoryStream", NULL }, _tf_ssb_rpc_createHistoryStream, NULL, NULL); /* SOURCE */
|
tf_ssb_add_rpc_callback(ssb, "createHistoryStream", _tf_ssb_rpc_createHistoryStream, NULL, NULL); /* SOURCE */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "ebt", "replicate", NULL }, _tf_ssb_rpc_ebt_replicate_server, NULL, NULL); /* DUPLEX */
|
tf_ssb_add_rpc_callback(ssb, "ebt.replicate", _tf_ssb_rpc_ebt_replicate_server, NULL, NULL); /* DUPLEX */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "peers", "exchange", NULL }, _tf_ssb_rpc_peers_exchange, NULL, NULL); /* ASYNC */
|
tf_ssb_add_rpc_callback(ssb, "peers.exchange", _tf_ssb_rpc_peers_exchange, NULL, NULL); /* ASYNC */
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
#define VERSION_NUMBER "0.0.22"
|
#define VERSION_NUMBER "0.0.24-wip"
|
||||||
#define VERSION_NAME "Get born soon."
|
#define VERSION_NAME "Honey bunches of boats."
|
||||||
|
@ -25,6 +25,30 @@ try:
|
|||||||
#options.add_argument('--headless')
|
#options.add_argument('--headless')
|
||||||
driver = webdriver.Firefox(options = options, service = service)
|
driver = webdriver.Firefox(options = options, service = service)
|
||||||
wait = WebDriverWait(driver, 10)
|
wait = WebDriverWait(driver, 10)
|
||||||
|
|
||||||
|
driver.get('http://localhost:8888')
|
||||||
|
driver.find_element(By.TAG_NAME, 'tf-navigation').shadow_root.find_element(By.LINK_TEXT, 'login').click()
|
||||||
|
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'register_label').click()
|
||||||
|
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'name').send_keys('adminuser')
|
||||||
|
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'password').send_keys('admin_password')
|
||||||
|
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'confirm').send_keys('admin_password')
|
||||||
|
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'loginButton').click()
|
||||||
|
wait.until(expected_conditions.presence_of_element_located((By.ID, 'document')))
|
||||||
|
driver.switch_to.frame(driver.find_element(By.ID, 'document'))
|
||||||
|
wait.until(expected_conditions.presence_of_element_located((By.LINK_TEXT, 'identity')))
|
||||||
|
driver.switch_to.default_content()
|
||||||
|
|
||||||
|
driver.get('http://localhost:8888/~core/admin/')
|
||||||
|
wait.until(expected_conditions.presence_of_element_located((By.ID, 'document')))
|
||||||
|
driver.switch_to.frame(driver.find_element(By.ID, 'document'))
|
||||||
|
wait.until(expected_conditions.presence_of_element_located((By.ID, 'gs_room_name'))).send_keys('test room')
|
||||||
|
wait.until(expected_conditions.presence_of_element_located((By.XPATH, '//*[@id="gs_room_name"]/following-sibling::button'))).click()
|
||||||
|
driver.switch_to.alert.accept()
|
||||||
|
driver.switch_to.default_content()
|
||||||
|
|
||||||
|
driver.find_element(By.TAG_NAME, 'tf-navigation').shadow_root.find_element(By.ID, 'identity').click()
|
||||||
|
driver.find_element(By.TAG_NAME, 'tf-navigation').shadow_root.find_element(By.ID, 'logout').click()
|
||||||
|
|
||||||
driver.get('http://localhost:8888')
|
driver.get('http://localhost:8888')
|
||||||
driver.find_element(By.TAG_NAME, 'tf-navigation').shadow_root.find_element(By.LINK_TEXT, 'login').click()
|
driver.find_element(By.TAG_NAME, 'tf-navigation').shadow_root.find_element(By.LINK_TEXT, 'login').click()
|
||||||
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'register_label').click()
|
driver.find_element(By.TAG_NAME, 'tf-auth').shadow_root.find_element(By.ID, 'register_label').click()
|
||||||
@ -82,13 +106,6 @@ try:
|
|||||||
driver.switch_to.frame(wait.until(expected_conditions.presence_of_element_located((By.ID, 'document'))))
|
driver.switch_to.frame(wait.until(expected_conditions.presence_of_element_located((By.ID, 'document'))))
|
||||||
id1 = wait.until(expected_conditions.presence_of_element_located((By.TAG_NAME, 'li'))).text.split(' ')[-1]
|
id1 = wait.until(expected_conditions.presence_of_element_located((By.TAG_NAME, 'li'))).text.split(' ')[-1]
|
||||||
|
|
||||||
driver.get('http://localhost:8888/~core/admin/')
|
|
||||||
wait.until(expected_conditions.presence_of_element_located((By.ID, 'document')))
|
|
||||||
driver.switch_to.frame(driver.find_element(By.ID, 'document'))
|
|
||||||
wait.until(expected_conditions.presence_of_element_located((By.ID, 'gs_room_name'))).send_keys('test room')
|
|
||||||
wait.until(expected_conditions.presence_of_element_located((By.XPATH, '//*[@id="gs_room_name"]/following-sibling::button'))).click()
|
|
||||||
driver.switch_to.alert.accept()
|
|
||||||
|
|
||||||
driver.get('http://localhost:8888')
|
driver.get('http://localhost:8888')
|
||||||
wait.until(expected_conditions.presence_of_element_located((By.ID, 'document')))
|
wait.until(expected_conditions.presence_of_element_located((By.ID, 'document')))
|
||||||
driver.switch_to.frame(driver.find_element(By.ID, 'document'))
|
driver.switch_to.frame(driver.find_element(By.ID, 'document'))
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
if [ -z $ANDROID_NDK_ROOT ]; then
|
if [ -z $ANDROID_NDK_ROOT ]; then
|
||||||
ANDROID_NDK_ROOT=~/Android/Sdk/ndk/26.1.10909125
|
ANDROID_NDK_ROOT=~/Android/Sdk/ndk/26.1.10909125
|
||||||
fi
|
fi
|
||||||
OPENSSL_VERSION=3.3.1
|
|
||||||
|
|
||||||
API_LEVEL=24
|
API_LEVEL=24
|
||||||
|
|
||||||
@ -11,7 +10,7 @@ BUILD_DIR=out/openssl_android_build
|
|||||||
|
|
||||||
BUILD_TARGETS="x86_64 x86 arm64-v8a armeabi-v7a"
|
BUILD_TARGETS="x86_64 x86 arm64-v8a armeabi-v7a"
|
||||||
|
|
||||||
WORK_DIR=out/openssl-${OPENSSL_VERSION}-android
|
WORK_DIR=out/openssl-android
|
||||||
rm -rf $WORK_DIR
|
rm -rf $WORK_DIR
|
||||||
cp -arf deps/openssl_src/ $WORK_DIR
|
cp -arf deps/openssl_src/ $WORK_DIR
|
||||||
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
OPENSSL_VERSION=3.3.1
|
|
||||||
|
|
||||||
API_LEVEL=28
|
API_LEVEL=28
|
||||||
|
|
||||||
BUILD_DIR=out/openssl_ios_build
|
BUILD_DIR=out/openssl_ios_build
|
||||||
|
|
||||||
BUILD_TARGETS="ios64-xcrun iossimulator-xcrun"
|
BUILD_TARGETS="ios64-xcrun iossimulator-xcrun"
|
||||||
|
|
||||||
WORK_DIR=out/openssl-${OPENSSL_VERSION}-ios
|
WORK_DIR=out/openssl-ios
|
||||||
rm -rf $WORK_DIR
|
rm -rf $WORK_DIR
|
||||||
cp -af deps/openssl_src/ $WORK_DIR
|
cp -af deps/openssl_src/ $WORK_DIR
|
||||||
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
OPENSSL_VERSION=3.3.1
|
|
||||||
|
|
||||||
API_LEVEL=24
|
API_LEVEL=24
|
||||||
|
|
||||||
BUILD_DIR=out/openssl_mingw64_build
|
BUILD_DIR=out/openssl_mingw64_build
|
||||||
|
|
||||||
BUILD_TARGETS="mingw64"
|
BUILD_TARGETS="mingw64"
|
||||||
|
|
||||||
WORK_DIR=out/openssl-${OPENSSL_VERSION}-mingw64
|
WORK_DIR=out/openssl-mingw64
|
||||||
rm -rf $WORK_DIR
|
rm -rf $WORK_DIR
|
||||||
cp -arf deps/openssl_src/ $WORK_DIR
|
cp -arf deps/openssl_src/ $WORK_DIR
|
||||||
|
|
||||||
@ -65,9 +63,9 @@ build_the_thing() {
|
|||||||
-DOPENSSL_SMALL_FOOTPRINT"
|
-DOPENSSL_SMALL_FOOTPRINT"
|
||||||
echo "./Configure $SSL_TARGET $OPTIONS $GLOBAL_OPTIONS" && \
|
echo "./Configure $SSL_TARGET $OPTIONS $GLOBAL_OPTIONS" && \
|
||||||
./Configure $SSL_TARGET $OPTIONS $GLOBAL_OPTIONS && \
|
./Configure $SSL_TARGET $OPTIONS $GLOBAL_OPTIONS && \
|
||||||
make clean && \
|
make -s clean && \
|
||||||
make build_generated && \
|
make -s build_generated && \
|
||||||
make libcrypto.a libssl.a || exit 128
|
make -s libcrypto.a libssl.a || exit 128
|
||||||
}
|
}
|
||||||
|
|
||||||
for build_target in $BUILD_TARGETS
|
for build_target in $BUILD_TARGETS
|
||||||
|
Reference in New Issue
Block a user