forked from cory/tildefriends
Compare commits
7 Commits
user_setti
...
v0.0.17
Author | SHA1 | Date | |
---|---|---|---|
3c0b680b8e | |||
895356897b | |||
9164be2f37 | |||
5385264f94 | |||
610e756c07 | |||
15c9f8f458 | |||
fb704a5b83 |
44
GNUmakefile
44
GNUmakefile
@ -4,7 +4,7 @@ MAKEFLAGS += --warn-undefined-variables
|
|||||||
MAKEFLAGS += --no-builtin-rules
|
MAKEFLAGS += --no-builtin-rules
|
||||||
|
|
||||||
VERSION_CODE := 17
|
VERSION_CODE := 17
|
||||||
VERSION_NUMBER := 0.0.17-wip
|
VERSION_NUMBER := 0.0.17
|
||||||
VERSION_NAME := Please enjoy responsibly.
|
VERSION_NAME := Please enjoy responsibly.
|
||||||
|
|
||||||
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3450200.zip
|
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3450200.zip
|
||||||
@ -17,18 +17,6 @@ UNAME_M := $(shell uname -m)
|
|||||||
|
|
||||||
ANDROID_SDK ?= ~/Android/Sdk
|
ANDROID_SDK ?= ~/Android/Sdk
|
||||||
|
|
||||||
ifeq ($(UNAME_M),x86_64)
|
|
||||||
ifneq ($(UNAME_S),Haiku)
|
|
||||||
debug: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
|
|
||||||
debug: LDFLAGS += -fsanitize=address -fsanitize=undefined
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(UNAME_M),aarch64)
|
|
||||||
debug: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
|
|
||||||
debug: LDFLAGS += -fsanitize=address -fsanitize=undefined
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
ifeq ($(UNAME_S),Darwin)
|
||||||
BUILD_TYPES := macosdebug macosrelease iosdebug iosrelease iossimdebug iossimrelease
|
BUILD_TYPES := macosdebug macosrelease iosdebug iosrelease iossimdebug iossimrelease
|
||||||
else ifeq ($(UNAME_S),Linux)
|
else ifeq ($(UNAME_S),Linux)
|
||||||
@ -222,6 +210,18 @@ $(IOS_TARGETS): LDFLAGS += -Ldeps/openssl/ios/ios64-xcrun/usr/local/lib
|
|||||||
$(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/include
|
$(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/include
|
||||||
$(IOSSIM_TARGETS): LDFLAGS += -Ldeps/openssl/ios/iossimulator-xcrun/usr/local/lib
|
$(IOSSIM_TARGETS): LDFLAGS += -Ldeps/openssl/ios/iossimulator-xcrun/usr/local/lib
|
||||||
|
|
||||||
|
ifeq ($(UNAME_M),x86_64)
|
||||||
|
ifneq ($(UNAME_S),Haiku)
|
||||||
|
out/debug/tildefriends: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
|
||||||
|
out/debug/tildefriends: LDFLAGS += -fsanitize=address -fsanitize=undefined
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME_M),aarch64)
|
||||||
|
out/debug/tildefriends: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
|
||||||
|
out/debug/tildefriends: LDFLAGS += -fsanitize=address -fsanitize=undefined
|
||||||
|
endif
|
||||||
|
|
||||||
get_objs = \
|
get_objs = \
|
||||||
$(foreach build_type,$(BUILD_TYPES),$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)))))) \
|
$(foreach build_type,$(BUILD_TYPES),$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)))))) \
|
||||||
$(foreach build_type,debug release,$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)_unix))))) \
|
$(foreach build_type,debug release,$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)_unix))))) \
|
||||||
@ -578,7 +578,7 @@ $(MINIUNZIP_OBJS): CFLAGS += \
|
|||||||
LDFLAGS += \
|
LDFLAGS += \
|
||||||
-pthread \
|
-pthread \
|
||||||
-lm
|
-lm
|
||||||
debug release $(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
$(LINUX_TARGETS) $(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
||||||
-lssl \
|
-lssl \
|
||||||
-lcrypto
|
-lcrypto
|
||||||
ifneq ($(UNAME_S),Haiku)
|
ifneq ($(UNAME_S),Haiku)
|
||||||
@ -728,7 +728,7 @@ out/apk/TildeFriends-arm-%.unsigned.apk:
|
|||||||
@cp out/apk/res.apk $@.zip
|
@cp out/apk/res.apk $@.zip
|
||||||
@cp out/apk/classes.dex out/apk-arm-$(BUILD_TYPE)/
|
@cp out/apk/classes.dex out/apk-arm-$(BUILD_TYPE)/
|
||||||
@cd out/apk-arm-$(BUILD_TYPE) && zip -u ../../$@.zip -q -9 -r . && cd ../../
|
@cd out/apk-arm-$(BUILD_TYPE) && zip -u ../../$@.zip -q -9 -r . && cd ../../
|
||||||
@zip -u $@.zip -q $(RAW_FILES)
|
@zip -u $@.zip -q -9 $(RAW_FILES)
|
||||||
@$(ANDROID_BUILD_TOOLS)/zipalign -f 4 $@.zip $@
|
@$(ANDROID_BUILD_TOOLS)/zipalign -f 4 $@.zip $@
|
||||||
|
|
||||||
out/apk/TildeFriends-x86-%.unsigned.apk:
|
out/apk/TildeFriends-x86-%.unsigned.apk:
|
||||||
@ -741,7 +741,7 @@ out/apk/TildeFriends-x86-%.unsigned.apk:
|
|||||||
@cp out/apk/res.apk $@.zip
|
@cp out/apk/res.apk $@.zip
|
||||||
@cp out/apk/classes.dex out/apk-x86-$(BUILD_TYPE)/
|
@cp out/apk/classes.dex out/apk-x86-$(BUILD_TYPE)/
|
||||||
@cd out/apk-x86-$(BUILD_TYPE) && zip -u ../../$@.zip -q -9 -r . && cd ../../
|
@cd out/apk-x86-$(BUILD_TYPE) && zip -u ../../$@.zip -q -9 -r . && cd ../../
|
||||||
@zip -u $@.zip -q $(RAW_FILES)
|
@zip -u $@.zip -q -9 $(RAW_FILES)
|
||||||
@$(ANDROID_BUILD_TOOLS)/zipalign -f 4 $@.zip $@
|
@$(ANDROID_BUILD_TOOLS)/zipalign -f 4 $@.zip $@
|
||||||
|
|
||||||
out/%.apk: out/apk/%.unsigned.apk
|
out/%.apk: out/apk/%.unsigned.apk
|
||||||
@ -769,10 +769,10 @@ out/%.app/tildefriends.png: src/ios/tildefriends.png
|
|||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
@cp -v $< $@
|
@cp -v $< $@
|
||||||
|
|
||||||
out/%/data.zip: $(RAW_FILES)
|
out/data.zip: $(RAW_FILES)
|
||||||
@zip -u $@ -q -9 $(RAW_FILES)
|
@zip -u $@ -q -9 $(RAW_FILES)
|
||||||
|
|
||||||
out/tildefriends-%.app/tildefriends: out/%/tildefriends out/tildefriends-%.app/Info.plist out/tildefriends-%.app/tildefriends.png out/tildefriends-%.app/data.zip
|
out/tildefriends-%.app/tildefriends: out/%/tildefriends out/tildefriends-%.app/Info.plist out/tildefriends-%.app/tildefriends.png out/data.zip
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
@cp -v $< $@
|
@cp -v $< $@
|
||||||
ifeq ($(HAVE_LINUX_IOS),1)
|
ifeq ($(HAVE_LINUX_IOS),1)
|
||||||
@ -787,6 +787,12 @@ out/tildefriends-%.ipa: out/tildefriends-ios%.app/tildefriends
|
|||||||
@cd $@.tmp/ && zip -u ../../$@ -q -9 -r ./
|
@cd $@.tmp/ && zip -u ../../$@ -q -9 -r ./
|
||||||
@rm -rf $@.tmp/
|
@rm -rf $@.tmp/
|
||||||
|
|
||||||
|
|
||||||
|
out/%/tildefriends.standalone: out/%/tildefriends out/data.zip
|
||||||
|
@echo "[standalone] $@"
|
||||||
|
@cat $< out/data.zip > $@
|
||||||
|
@chmod +x $@
|
||||||
|
|
||||||
iossimdebug-app: out/tildefriends-iossimdebug.app/tildefriends
|
iossimdebug-app: out/tildefriends-iossimdebug.app/tildefriends
|
||||||
iossimrelease-app: out/tildefriends-iossimrelease.app/tildefriends
|
iossimrelease-app: out/tildefriends-iossimrelease.app/tildefriends
|
||||||
iosdebug-app: out/tildefriends-iosdebug.app/tildefriends
|
iosdebug-app: out/tildefriends-iosdebug.app/tildefriends
|
||||||
@ -851,7 +857,7 @@ dist: release-apk iosrelease-ipa
|
|||||||
@echo [archive] dist/tildefriends-$(VERSION_NUMBER).tar.xz
|
@echo [archive] dist/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 dist/ out/tildefriends-$(VERSION_NUMBER)
|
||||||
@git archive main | tar -x -C out/tildefriends-$(VERSION_NUMBER)
|
@git archive HEAD | tar -x -C out/tildefriends-$(VERSION_NUMBER)
|
||||||
@tar \
|
@tar \
|
||||||
--exclude=apps/welcome* \
|
--exclude=apps/welcome* \
|
||||||
--exclude=deps/libbacktrace/Isaac.Newton-Opticks.txt \
|
--exclude=deps/libbacktrace/Isaac.Newton-Opticks.txt \
|
||||||
|
5
apps/identity.json
Normal file
5
apps/identity.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"type": "tildefriends-app",
|
||||||
|
"emoji": "🪪",
|
||||||
|
"previous": "&kgukkyDk1RxgfzgMH6H/0QeDPIuwPZypLuAFax21ljk=.sha256"
|
||||||
|
}
|
93
apps/identity/app.js
Normal file
93
apps/identity/app.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import * as tfrpc from '/tfrpc.js';
|
||||||
|
|
||||||
|
tfrpc.register(async function get_private_key(id) {
|
||||||
|
return bip39Words(await ssb.getPrivateKey(id));
|
||||||
|
});
|
||||||
|
tfrpc.register(async function create_id(id) {
|
||||||
|
return await ssb.createIdentity();
|
||||||
|
});
|
||||||
|
tfrpc.register(async function add_id(id) {
|
||||||
|
return await ssb.addIdentity(bip39Bytes(id));
|
||||||
|
});
|
||||||
|
tfrpc.register(async function delete_id(id) {
|
||||||
|
return await ssb.deleteIdentity(id);
|
||||||
|
});
|
||||||
|
tfrpc.register(async function reload() {
|
||||||
|
await main();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
let ids = await ssb.getIdentities();
|
||||||
|
await app.setDocument(
|
||||||
|
`<body style="color: #fff">
|
||||||
|
<script>const handler = {};</script>
|
||||||
|
<script type="module">
|
||||||
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
|
handler.export_id = async function export_id(event) {
|
||||||
|
let id = event.srcElement.dataset.id;
|
||||||
|
let element = document.createElement('textarea');
|
||||||
|
element.value = await tfrpc.rpc.get_private_key(id);
|
||||||
|
element.style = 'width: 100%; read-only: true';
|
||||||
|
element.readOnly = true;
|
||||||
|
event.srcElement.parentElement.appendChild(element);
|
||||||
|
event.srcElement.onclick = event => handler.hide_id(event, element);
|
||||||
|
}
|
||||||
|
handler.add_id = async function add_id(event) {
|
||||||
|
let id = document.getElementById('add_id').value;
|
||||||
|
try {
|
||||||
|
let new_id = await tfrpc.rpc.add_id(id);
|
||||||
|
alert('Successfully imported: ' + new_id);
|
||||||
|
await tfrpc.rpc.reload();
|
||||||
|
} catch (e) {
|
||||||
|
alert('Error importing identity: ' + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handler.create_id = async function create_id(event) {
|
||||||
|
try {
|
||||||
|
let id = await tfrpc.rpc.create_id();
|
||||||
|
alert('Successfully created: ' + id);
|
||||||
|
await tfrpc.rpc.reload();
|
||||||
|
} catch (e) {
|
||||||
|
alert('Error creating identity: ' + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handler.hide_id = function hide_id(event, element) {
|
||||||
|
element.parentNode.removeChild(element);
|
||||||
|
event.srcElement.onclick = handler.export_id;
|
||||||
|
}
|
||||||
|
handler.delete_id = async function delete_id(event) {
|
||||||
|
let id = event.srcElement.dataset.id;
|
||||||
|
try {
|
||||||
|
if (prompt('Are you sure you want to delete "' + id + '"? It cannot be recovered without the exported phrase.\\n\\nEnter the word "DELETE" to confirm you wish to delete it.') === 'DELETE') {
|
||||||
|
if (await tfrpc.rpc.delete_id(id)) {
|
||||||
|
alert('Successfully deleted ID: ' + id);
|
||||||
|
}
|
||||||
|
await tfrpc.rpc.reload();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert('Error deleting ID: ' + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<h1>SSB Identity Management</h1>
|
||||||
|
<h2>Create a new identity</h2>
|
||||||
|
<button id="create_id" onclick="handler.create_id()">Create Identity</button>
|
||||||
|
<h2>Import an SSB Identity from 12 BIP39 English Words</h2>
|
||||||
|
<textarea id="add_id" style="width: 100%" rows="4"></textarea><button id="add" onclick="handler.add_id(event)">Import Identity</button>
|
||||||
|
<h2>Identities</h2>
|
||||||
|
<ul>` +
|
||||||
|
ids
|
||||||
|
.map(
|
||||||
|
(id) => `<li>
|
||||||
|
<button onclick="handler.export_id(event)" data-id="${id}">Export Identity</button>
|
||||||
|
<button onclick="handler.delete_id(event)" data-id="${id}">Delete Identity</button>
|
||||||
|
${id}
|
||||||
|
</li>`
|
||||||
|
)
|
||||||
|
.join('\n') +
|
||||||
|
` </ul>
|
||||||
|
</body>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
@ -1 +0,0 @@
|
|||||||
{"type": "tildefriends-app", "emoji": "⚙️"}
|
|
@ -1,60 +0,0 @@
|
|||||||
import * as tfrpc from '/tfrpc.js';
|
|
||||||
|
|
||||||
tfrpc.register(async function getIdentities() {
|
|
||||||
return ssb.getIdentities();
|
|
||||||
});
|
|
||||||
tfrpc.register(async function createID(id) {
|
|
||||||
return await ssb.createIdentity();
|
|
||||||
});
|
|
||||||
tfrpc.register(async function getPrivateKey(id) {
|
|
||||||
return bip39Words(await ssb.getPrivateKey(id));
|
|
||||||
});
|
|
||||||
tfrpc.register(async function addID(id) {
|
|
||||||
return await ssb.addIdentity(bip39Bytes(id));
|
|
||||||
});
|
|
||||||
tfrpc.register(async function deleteID(id) {
|
|
||||||
return await ssb.deleteIdentity(id);
|
|
||||||
});
|
|
||||||
tfrpc.register(async function getThemes() {
|
|
||||||
// TODO
|
|
||||||
return ['solarized', 'gruvbox', 'light'];
|
|
||||||
});
|
|
||||||
tfrpc.register(async function getTheme() {
|
|
||||||
// TODO
|
|
||||||
return 'gruvbox';
|
|
||||||
});
|
|
||||||
tfrpc.register(async function setTheme() {
|
|
||||||
// TODO
|
|
||||||
console.warn('setTheme called - not implemented');
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
tfrpc.register(async function reload() {
|
|
||||||
await main();
|
|
||||||
});
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
// Get body.html
|
|
||||||
const body = utf8Decode(await getFile('body.html'));
|
|
||||||
|
|
||||||
// Build the document
|
|
||||||
const document = `
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link rel="stylesheet" href="/static/tildefriends-v1.css"/>
|
|
||||||
<script src="tf-theme-picker.js" type="module"></script>
|
|
||||||
<script src="tf-password-form.js" type="module"></script>
|
|
||||||
<script src="tf-delete-account-btn.js" type="module"></script>
|
|
||||||
<script src="tf-identity-manager.js" type="module"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="flex-column">
|
|
||||||
${body}
|
|
||||||
</body>
|
|
||||||
</html>`;
|
|
||||||
|
|
||||||
// Send it to the browser
|
|
||||||
app.setDocument(document);
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
@ -1,20 +0,0 @@
|
|||||||
<h1>Your settings</h1>
|
|
||||||
|
|
||||||
<div class="box flex-column">
|
|
||||||
<h2>Appearance</h2>
|
|
||||||
|
|
||||||
<tf-theme-picker></tf-theme-picker>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="box flex-column">
|
|
||||||
<h2>Danger Zone</h2>
|
|
||||||
|
|
||||||
<h3>Manage your identities</h3>
|
|
||||||
<tf-identity-manager></tf-identity-manager>
|
|
||||||
|
|
||||||
<h3>Change my password</h3>
|
|
||||||
<tf-password-form></tf-password-form>
|
|
||||||
|
|
||||||
<h3>Delete your account</h3>
|
|
||||||
<tf-delete-account-btn></tf-delete-account-btn>
|
|
||||||
</div>
|
|
120
apps/user_settings/lit-all.min.js
vendored
120
apps/user_settings/lit-all.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,36 +0,0 @@
|
|||||||
import {LitElement, html} from './lit-all.min.js';
|
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
|
||||||
|
|
||||||
class TfDeleteAccountButtonElement extends LitElement {
|
|
||||||
static get properties() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteAccount() {
|
|
||||||
const res = confirm(
|
|
||||||
'Are you really sure you want to delete your account ?'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!res) return;
|
|
||||||
|
|
||||||
console.warn('TODO');
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`
|
|
||||||
<link rel="stylesheet" href="/static/tildefriends-v1.css" />
|
|
||||||
|
|
||||||
<span>This action is irreversible !</span>
|
|
||||||
|
|
||||||
<button class="red" @click=${this.deleteAccount}>
|
|
||||||
[Not implemented] Delete my Tilde Friends account
|
|
||||||
</button>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define('tf-delete-account-btn', TfDeleteAccountButtonElement);
|
|
@ -1,118 +0,0 @@
|
|||||||
import {LitElement, html} from './lit-all.min.js';
|
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
|
||||||
|
|
||||||
class TfIdentityManagerElement extends LitElement {
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
ids: {type: Array},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.ids = [];
|
|
||||||
this.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
async load() {
|
|
||||||
this.ids = await tfrpc.rpc.getIdentities();
|
|
||||||
}
|
|
||||||
|
|
||||||
async createIdentity() {
|
|
||||||
try {
|
|
||||||
const id = await tfrpc.rpc.createID();
|
|
||||||
alert('Successfully created: ' + id);
|
|
||||||
await tfrpc.rpc.reload();
|
|
||||||
} catch (err) {
|
|
||||||
alert('Error creating identity: ' + err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async importIdentity() {
|
|
||||||
const words = this.renderRoot?.querySelector('#import-id-textarea').value;
|
|
||||||
if (!words) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const newID = await tfrpc.rpc.addID(words);
|
|
||||||
|
|
||||||
if (newID) alert('Successfully imported a new identity.');
|
|
||||||
else alert('This identity already exists or is invalid.');
|
|
||||||
await tfrpc.rpc.reload();
|
|
||||||
} catch (err) {
|
|
||||||
alert('Error importing identity: ' + err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async exportIdentity(id) {
|
|
||||||
alert(
|
|
||||||
'Your private key is:\n' +
|
|
||||||
(await tfrpc.rpc.getPrivateKey(id)) +
|
|
||||||
'\nDo not share it with anyone!'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteIdentity(id) {
|
|
||||||
try {
|
|
||||||
if (
|
|
||||||
prompt(
|
|
||||||
'Are you sure you want to delete "' +
|
|
||||||
id +
|
|
||||||
'"? It cannot be recovered without the exported phrase.\\n\\nEnter the word "DELETE" to confirm you wish to delete it.'
|
|
||||||
) === 'DELETE'
|
|
||||||
) {
|
|
||||||
if (await tfrpc.rpc.deleteID(id)) {
|
|
||||||
alert('Successfully deleted ID: ' + id);
|
|
||||||
}
|
|
||||||
await tfrpc.rpc.reload();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
alert('Error deleting ID: ' + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html` <link rel="stylesheet" href="/static/tildefriends-v1.css" />
|
|
||||||
<style>
|
|
||||||
.id-span {
|
|
||||||
font-family: monospace;
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<h4>Create a new identity</h4>
|
|
||||||
<button id="create-id" class="green" @click=${this.createIdentity}>
|
|
||||||
Create Identity
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<h4>Import an SSB Identity from 12 BIP39 English Words</h4>
|
|
||||||
<textarea id="import-id-textarea" style="width: 100%" rows="4"></textarea>
|
|
||||||
<button class="green" @click=${this.importIdentity}>
|
|
||||||
Import Identity
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<h4>Warning !</h4>
|
|
||||||
<strong
|
|
||||||
>Anybody that knows your private key can gain total access over your
|
|
||||||
account.</strong
|
|
||||||
>
|
|
||||||
<br /><br />
|
|
||||||
Tilde Friends' contributors will never ask you for your private key !
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
${this.ids.map(
|
|
||||||
(id) =>
|
|
||||||
html` <li>
|
|
||||||
<button class="blue" @click=${() => this.exportIdentity(id)}>
|
|
||||||
Export Identity
|
|
||||||
</button>
|
|
||||||
<button class="red" @click=${() => this.deleteIdentity(id)}>
|
|
||||||
Delete Identity
|
|
||||||
</button>
|
|
||||||
<span class="id-span">${id}</span>
|
|
||||||
</li>`
|
|
||||||
)}
|
|
||||||
</ul>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define('tf-identity-manager', TfIdentityManagerElement);
|
|
@ -1,82 +0,0 @@
|
|||||||
import {LitElement, html} from './lit-all.min.js';
|
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
|
||||||
|
|
||||||
class TfPasswordFormElement extends LitElement {
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
//selected: {type: String},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks a password against different requirements
|
|
||||||
* @param {string} password the password to validate
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
validatePassword(password) {
|
|
||||||
// TODO(tasiaiso)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
submitPassword() {
|
|
||||||
const currentPwd = this.shadowRoot.getElementById('current').value;
|
|
||||||
const newPwd = this.shadowRoot.getElementById('new').value;
|
|
||||||
const repeatPwd = this.shadowRoot.getElementById('Repeat').value;
|
|
||||||
|
|
||||||
if (!(newPwd === repeatPwd)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// tfrpc.changePassword()
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`
|
|
||||||
<link rel="stylesheet" href="/static/tildefriends-v1.css" />
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: auto auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="grid">
|
|
||||||
<label for="current">Current password:</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
id="current"
|
|
||||||
name="current"
|
|
||||||
autocomplete="current-password"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<label for="new">Enter new password:</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
id="new"
|
|
||||||
name="new"
|
|
||||||
autocomplete="new-password"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<label for="repeat">Repeat new password:</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
id="repeat"
|
|
||||||
name="repeat"
|
|
||||||
autocomplete="new-password"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button @click=${this.submitPassword} class="red">
|
|
||||||
[Not implemented] Change my password
|
|
||||||
</button>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define('tf-password-form', TfPasswordFormElement);
|
|
@ -1,51 +0,0 @@
|
|||||||
import {LitElement, html, nothing} from './lit-all.min.js';
|
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
|
||||||
|
|
||||||
class TfThemePickerElement extends LitElement {
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
selected: {type: String},
|
|
||||||
themes: {type: Array},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
async load() {
|
|
||||||
this.themes = await tfrpc.rpc.getThemes();
|
|
||||||
this.selected = await tfrpc.rpc.getTheme();
|
|
||||||
|
|
||||||
let select = this.renderRoot?.querySelector('#theme-select');
|
|
||||||
select.value = this.selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
changed(event) {
|
|
||||||
this.selected = event.srcElement.value;
|
|
||||||
console.log('selected theme', this.selected);
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`
|
|
||||||
<link rel="stylesheet" href="/static/tildefriends-v1.css" />
|
|
||||||
|
|
||||||
<label for="theme">[Not implemented] Choose your theme:</label>
|
|
||||||
|
|
||||||
<select
|
|
||||||
name="theme"
|
|
||||||
id="theme-select"
|
|
||||||
?hidden=${!this.themes?.length}
|
|
||||||
@change=${this.changed}
|
|
||||||
>
|
|
||||||
${(this.themes ?? []).map(
|
|
||||||
(name) => html`<option value=${name}>${name}</option>`
|
|
||||||
)}
|
|
||||||
</select>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define('tf-theme-picker', TfThemePickerElement);
|
|
BIN
bleh.tar.xz
BIN
bleh.tar.xz
Binary file not shown.
@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Tilde Friends core stylesheet
|
|
||||||
*
|
|
||||||
* This Software is an external library that is part of
|
|
||||||
* Tilde Friends and is shared under the MIT license.
|
|
||||||
*
|
|
||||||
* Inject this file in your app at tildefriends.css
|
|
||||||
* and use this tag to import it:
|
|
||||||
* <link rel="stylesheet" href="/static/tildefriends-v1.css"/>
|
|
||||||
*
|
|
||||||
* v1.0 / 2024 M03 21
|
|
||||||
*/
|
|
||||||
|
|
||||||
body {
|
|
||||||
color: white;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
.button,
|
|
||||||
input[type='button'],
|
|
||||||
input[type='submit'],
|
|
||||||
select {
|
|
||||||
border: none;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 8px 12px;
|
|
||||||
text-align: center;
|
|
||||||
text-decoration: none;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 4px;
|
|
||||||
|
|
||||||
&.red {
|
|
||||||
background-color: #bd1e24;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.green {
|
|
||||||
background-color: #18922d;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.blue {
|
|
||||||
background-color: #0067a7;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.yellow {
|
|
||||||
background-color: #ee9600;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
filter: brightness(0.75);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a:link {
|
|
||||||
color: #268bd2;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:visited {
|
|
||||||
color: #6c71c4;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #859900;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:active {
|
|
||||||
color: #2aa198;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
td,
|
|
||||||
th {
|
|
||||||
border: 1px solid #ffffff40;
|
|
||||||
text-align: left;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:nth-child(even) {
|
|
||||||
background-color: #ffffff20;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-column {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-row {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-flex-row {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box {
|
|
||||||
background-color: #00000020;
|
|
||||||
border: 1px solid grey;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 16px;
|
|
||||||
margin: 4px;
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
<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="17"
|
android:versionCode="17"
|
||||||
android:versionName="0.0.17-wip">
|
android:versionName="0.0.17">
|
||||||
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="34"/>
|
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="34"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<application
|
<application
|
||||||
|
@ -316,7 +316,9 @@ static void _file_read_file_zip_after_work(uv_work_t* work, int status)
|
|||||||
tf_trace_begin(trace, "file_read_zip_after_work");
|
tf_trace_begin(trace, "file_read_zip_after_work");
|
||||||
if (data->result >= 0)
|
if (data->result >= 0)
|
||||||
{
|
{
|
||||||
tf_task_resolve_promise(data->task, data->promise, tf_util_new_uint8_array(data->context, data->buffer, data->result));
|
JSValue array = tf_util_new_uint8_array(data->context, data->buffer, data->result);
|
||||||
|
tf_task_resolve_promise(data->task, data->promise, array);
|
||||||
|
JS_FreeValue(data->context, array);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
34
src/http.c
34
src/http.c
@ -161,10 +161,11 @@ static void _http_request_destroy(tf_http_request_t* request)
|
|||||||
tf_http_close_callback* on_close = request->on_close;
|
tf_http_close_callback* on_close = request->on_close;
|
||||||
if (on_close)
|
if (on_close)
|
||||||
{
|
{
|
||||||
|
tf_trace_t* trace = request->http->trace;
|
||||||
request->on_close = NULL;
|
request->on_close = NULL;
|
||||||
tf_trace_begin(request->http->trace, request->connection && request->connection->trace_name ? request->connection->trace_name : "websocket");
|
tf_trace_begin(trace, request->connection && request->connection->trace_name ? request->connection->trace_name : "websocket");
|
||||||
on_close(request);
|
on_close(request);
|
||||||
tf_trace_end(request->http->trace);
|
tf_trace_end(trace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,12 +175,9 @@ static void _http_connection_destroy(tf_http_connection_t* connection, const cha
|
|||||||
|
|
||||||
if (connection->request)
|
if (connection->request)
|
||||||
{
|
{
|
||||||
_http_request_destroy(connection->request);
|
tf_http_request_t* request = connection->request;
|
||||||
if (connection->request && connection->request->ref_count == 0)
|
|
||||||
{
|
|
||||||
tf_free(connection->request);
|
|
||||||
}
|
|
||||||
connection->request = NULL;
|
connection->request = NULL;
|
||||||
|
_http_request_destroy(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection->tcp.data && !uv_is_closing((uv_handle_t*)&connection->tcp))
|
if (connection->tcp.data && !uv_is_closing((uv_handle_t*)&connection->tcp))
|
||||||
@ -383,11 +381,19 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
|
|||||||
};
|
};
|
||||||
connection->request = request;
|
connection->request = request;
|
||||||
|
|
||||||
tf_http_request_ref(request);
|
if (!connection->http->is_shutting_down)
|
||||||
tf_trace_begin(connection->http->trace, connection->trace_name ? connection->trace_name : "http");
|
{
|
||||||
connection->callback(request);
|
tf_http_request_ref(request);
|
||||||
tf_trace_end(connection->http->trace);
|
tf_trace_begin(connection->http->trace, connection->trace_name ? connection->trace_name : "http");
|
||||||
tf_http_request_unref(request);
|
connection->callback(request);
|
||||||
|
tf_trace_end(connection->http->trace);
|
||||||
|
tf_http_request_unref(request);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char* k_payload = tf_http_status_text(503);
|
||||||
|
tf_http_respond(request, 503, NULL, 0, k_payload, strlen(k_payload));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -786,6 +792,8 @@ const char* tf_http_status_text(int status)
|
|||||||
return "File not found";
|
return "File not found";
|
||||||
case 500:
|
case 500:
|
||||||
return "Internal server error";
|
return "Internal server error";
|
||||||
|
case 503:
|
||||||
|
return "Service Unavailable";
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
@ -965,11 +973,11 @@ void tf_http_request_unref(tf_http_request_t* request)
|
|||||||
tf_http_connection_t* connection = request->connection;
|
tf_http_connection_t* connection = request->connection;
|
||||||
if (--request->ref_count == 0)
|
if (--request->ref_count == 0)
|
||||||
{
|
{
|
||||||
_http_request_destroy(request);
|
|
||||||
if (connection)
|
if (connection)
|
||||||
{
|
{
|
||||||
connection->request = NULL;
|
connection->request = NULL;
|
||||||
}
|
}
|
||||||
|
_http_request_destroy(request);
|
||||||
tf_free(request);
|
tf_free(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,7 +644,6 @@ static void _httpd_endpoint_static(tf_http_request_t* request)
|
|||||||
"style.css",
|
"style.css",
|
||||||
"tfrpc.js",
|
"tfrpc.js",
|
||||||
"w3.css",
|
"w3.css",
|
||||||
"tildefriends-v1.css"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* k_map[][2] = {
|
const char* k_map[][2] = {
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "backtrace.h"
|
#include "backtrace.h"
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
|
#include "unzip.h"
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -416,6 +417,14 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
|
|||||||
};
|
};
|
||||||
bool show_usage = false;
|
bool show_usage = false;
|
||||||
|
|
||||||
|
/* Check if the executable has data attached. */
|
||||||
|
unzFile zip = unzOpen(file);
|
||||||
|
if (zip)
|
||||||
|
{
|
||||||
|
args.zip = file;
|
||||||
|
unzClose(zip);
|
||||||
|
}
|
||||||
|
|
||||||
while (!show_usage)
|
while (!show_usage)
|
||||||
{
|
{
|
||||||
static const struct option k_options[] = {
|
static const struct option k_options[] = {
|
||||||
|
@ -1939,6 +1939,11 @@ void tf_task_destroy(tf_task_t* task)
|
|||||||
tf_free(task->_promise_stacks);
|
tf_free(task->_promise_stacks);
|
||||||
tf_free((void*)task->_path);
|
tf_free((void*)task->_path);
|
||||||
bool was_trusted = task->_trusted;
|
bool was_trusted = task->_trusted;
|
||||||
|
if (task->_zip)
|
||||||
|
{
|
||||||
|
unzClose(task->_zip);
|
||||||
|
task->_zip = NULL;
|
||||||
|
}
|
||||||
tf_free(task);
|
tf_free(task);
|
||||||
if (was_trusted)
|
if (was_trusted)
|
||||||
{
|
{
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
#define VERSION_NUMBER "0.0.17-wip"
|
#define VERSION_NUMBER "0.0.17"
|
||||||
#define VERSION_NAME "Please enjoy responsibly."
|
#define VERSION_NAME "Please enjoy responsibly."
|
||||||
|
Reference in New Issue
Block a user