local user database

This commit is contained in:
Believethehype
2024-02-13 12:58:19 +01:00
parent b61da7187d
commit 9f0ea60295
6 changed files with 266 additions and 274 deletions

View File

@@ -16,9 +16,7 @@ import {
import store from '../store';
import miniToastr from "mini-toastr";
import VueNotifications from "vue-notifications";
import searchdvms from './data/searchdvms.json'
import {computed, watch} from "vue";
import countries from "@/components/data/countries.json";
import deadnip89s from "@/components/data/deadnip89s.json";
import {data} from "autoprefixer";
import {requestProvider} from "webln";

View File

@@ -34,6 +34,7 @@
<h3 className="card-title">Nip07 Login</h3>
<p>Use a Browser Nip07 Extension like getalby or nos2x to login or use Amber on Android</p>
<button className="btn" @click="sign_in_nip07()">Browser Extension</button>
<!-- <button className="btn" @click="sign_in_nip46()">NsecBunker</button> Not working on server end rn.-->
<template v-if="supports_android_signer">
<button className="btn" @click="sign_in_amber()">Amber Sign in</button>
</template>
@@ -54,7 +55,17 @@ import {
Filter,
initLogger,
LogLevel,
Timestamp, Keys, NostrDatabase, ClientBuilder, ClientZapper, Alphabet, SingleLetterTag, Options, Duration, PublicKey
Timestamp,
Keys,
NostrDatabase,
ClientBuilder,
ClientZapper,
Alphabet,
SingleLetterTag,
Options,
Duration,
PublicKey,
Nip46Signer, NegentropyDirection, NegentropyOptions
} from "@rust-nostr/nostr-sdk";
import VueNotifications from "vue-notifications";
import store from '../store';
@@ -69,7 +80,8 @@ const isDark = useDark();
let nip89dvms = []
let logger = true
let logger = false
export default {
data() {
return {
@@ -223,12 +235,85 @@ export default {
localStorage.setItem('nostr-key', "")
console.log("Client connected")
await this.get_user_info(pubkey)
//await this.reconcile_all_profiles()
//miniToastr.showMessage("Login successful!", "Logged in as " + this.current_user, VueNotifications.types.success)
} catch (error) {
console.log(error);
}
},
async sign_in_nip46() {
try {
await loadWasmAsync();
let connectionstring = ""
if (localStorage.getItem('nostr-key') !== "" && localStorage.getItem('nostr-key').startsWith("nsecbunker://") ){
connectionstring = localStorage.getItem('nostr-key')
}
if (connectionstring === ""){
//ADD DEFAULT TEST STRING FOR NOW, USE USER INPUT LATER
connectionstring = "nsecbunker://npub1ffske30n349f7z3sccn6n90f9dxxqhcy5n4cgpq32355ka2ye6ls7sa6t4#7a53c7292aa6a8f731cd6fcc15b396213c6a7b0448f9e8994b2479f8832c029f?relay=wss://relay.nsecbunker.com"
}
if (connectionstring.startsWith("nsecbunker://")){
connectionstring = connectionstring.replace("nsecbunker://", "")
let split = connectionstring.split("?relay=")
let relay_url = split[1]
let split2 = split[0].split("#")
let publickey = Keys.fromPkStr(split2[0]).publicKey
let app_keys = Keys.fromSkStr(split2[1])
let nip46_signer = new Nip46Signer(relay_url, app_keys, publickey) ;
try{
this.signer = ClientSigner.nip46(nip46_signer);
console.log("SIGNER: " + this.signer)
} catch (error) {
console.log(error);
this.signer = ClientSigner.keys(Keys.generate())
}
//let zapper = ClientZapper.webln()
let opts = new Options().waitForSend(false).connectionTimeout(Duration.fromSecs(5));
let client = new ClientBuilder().signer(this.signer).opts(opts).build()
await client.addRelay(relay_url)
for (const relay of store.state.relays){
await client.addRelay(relay);
}
const pubkey = await nip46_signer.signerPublicKey()
console.log("PUBKEY : " + pubkey.toBech32())
await client.connect();
store.commit('set_client', client)
store.commit('set_pubkey', pubkey)
store.commit('set_hasEventListener', false)
localStorage.setItem('nostr-key-method', "nip46")
localStorage.setItem('nostr-key', connectionstring)
console.log("Client connected")
await this.get_user_info(pubkey)
//miniToastr.showMessage("Login successful!", "Logged in as " + this.current_user, VueNotifications.types.success)
}
else {
miniToastr.showMessage("Invalid Nsecbunker url")
}
} catch (error) {
console.log(error);
}
},
async sign_in_amber(key="") {
try {
@@ -334,7 +419,41 @@ export default {
},
async reconcile_all_profiles() {
let keys = Keys.fromSkStr("ece3c0aa759c3e895ecb3c13ab3813c0f98430c6d4bd22160b9c2219efc9cf0e")
let db = NostrDatabase.indexeddb("profiles");
let signer = ClientSigner.keys(keys) //TODO store keys
dbclient = new ClientBuilder().signer(signer).database(await db).build()
await dbclient.addRelay("wss://relay.damus.io");
await dbclient.connect();
let direction = NegentropyDirection.Down;
let opts = new NegentropyOptions().direction(direction);
let followings = []
let followers_filter = new Filter().author(store.state.pubkey).kind(3).limit(1)
let followers = await dbclient.getEventsOf([followers_filter], 10)
console.log(followers)
if (followers.length > 0){
console.log(followers.length)
for (let tag of followers[0].tags) {
console.log(tag.asVec())
if (tag.asVec()[0] === "p") {
let following = tag.asVec()[1]
followings.push(PublicKey.fromHex(following))
}
}
}
console.log("Followings: " + (followings.length).toString())
let filter = new Filter().kind(0).authors(followings)
await dbclient.reconcile(filter, opts);
},
async get_user_info(pubkey){
@@ -364,7 +483,7 @@ export default {
this.current_user = ""
localStorage.setItem('nostr-key-method', "anon")
localStorage.setItem('nostr-key', "")
await this.state.client.shutdown();
//await this.state.client.shutdown();
await this.sign_in_anon()
}
},

View File

@@ -1,4 +1,6 @@
<script setup>
import {
Client,
Filter,
@@ -9,14 +11,12 @@ import {
EventBuilder,
Tag,
EventId,
Nip19Event, Alphabet
Nip19Event, Alphabet, ClientBuilder, ClientSigner, Keys, NostrDatabase, NegentropyOptions, NegentropyDirection
} from "@rust-nostr/nostr-sdk";
import store from '../store';
import miniToastr from "mini-toastr";
import VueNotifications from "vue-notifications";
import searchdvms from './data/searchdvms.json'
import {computed, onMounted, ref} from "vue";
import countries from "@/components/data/countries.json";
import deadnip89s from "@/components/data/deadnip89s.json";
import amberSignerService from "./android-signer/AndroidSigner";
import VueDatePicker from '@vuepic/vue-datepicker';
@@ -28,13 +28,16 @@ let listener = false
let searching = false
const message = ref("");
const fromuser = ref("");
let dbclient = Client
let usernames = []
const datefrom = ref(new Date().setFullYear(new Date().getFullYear() - 1));
const dateto = ref(Date.now());
onMounted(async () => {
let urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('q')) {
@@ -42,6 +45,10 @@ onMounted(async () => {
await sleep(1000)
await send_search_request(message.value)
}
await sleep(1000)
await reconcile_all_profiles()
})
@@ -51,10 +58,48 @@ onMounted(async () => {
const sleep = (ms) => {
return new Promise(resolve => setTimeout(resolve, ms))
}
async function reconcile_all_profiles() {
if (store.state.pubkey !== undefined){
let keys = Keys.fromSkStr("ece3c0aa759c3e895ecb3c13ab3813c0f98430c6d4bd22160b9c2219efc9cf0e")
let db = NostrDatabase.indexeddb("profiles");
let signer = ClientSigner.keys(keys) //TODO store keys
dbclient = new ClientBuilder().signer(signer).database(await db).build()
await dbclient.addRelay("wss://relay.damus.io");
await dbclient.connect();
let direction = NegentropyDirection.Down;
let opts = new NegentropyOptions().direction(direction);
let followings = []
let followers_filter = new Filter().author(store.state.pubkey).kind(3).limit(1)
let followers = await dbclient.getEventsOf([followers_filter], 10)
if (followers.length > 0){
for (let tag of followers[0].tags) {
if (tag.asVec()[0] === "p") {
let following = tag.asVec()[1]
followings.push(PublicKey.fromHex(following))
}
}
}
console.log("Followings: " + (followings.length).toString())
let filter = new Filter().kind(0).authors(followings)
await dbclient.reconcile(filter, opts);
}
}
async function send_search_request(msg) {
try {
if (msg === undefined){
@@ -89,6 +134,12 @@ async function send_search_request(msg) {
users.push(pTag.asVec());
}
if (fromuser.value !== ""){
const userPubkey = PublicKey.fromBech32(fromuser.value.replace("@", "")).toHex()
const pTag = Tag.parse(["p", userPubkey]);
users.push(pTag.asVec());
}
msg = search.replace(/from:|to:|@/g, '').trim();
console.log(search);
@@ -166,15 +217,17 @@ async function getEvents(eventids) {
return await client.getEventsOf([event_filter], 5)
}
async function get_user_infos(pubkeys){
let profiles = []
let client = store.state.client
const profile_filter = new Filter().kind(0).authors(pubkeys)
let evts = await client.getEventsOf([profile_filter], 10)
console.log("PROFILES:" + evts.length)
for (const entry of evts){
try{
let contentjson = JSON.parse(entry.content)
console.log(contentjson)
profiles.push({profile: contentjson, author: entry.author.toHex(), createdAt: entry.createdAt});
}
catch(error){
@@ -309,12 +362,12 @@ async function listen() {
for (const evt of events) {
let p = profiles.find(record => record.author === evt.author.toHex())
let bech32id = evt.id.toBech32()
let nip19 = new Nip19Event(event.id, event.author, store.state.relays)
let nip19 = new Nip19Event(evt.id, evt.author, store.state.relays)
let nip19bech32 = nip19.toBech32()
let picture = p === undefined ? "../assets/nostr-purple.svg" : p["profile"]["picture"]
let name = p === undefined ? bech32id : p["profile"]["name"]
let highlighterurl = "https://highlighter.com/a/" + bech32id
let njumpurl = "https://njump.me/" + bech32id
let highlighterurl = "https://highlighter.com/e/" + nip19bech32
let njumpurl = "https://njump.me/" + nip19bech32
let nostrudelurl = "https://nostrudel.ninja/#/n/" + bech32id
let uri = "nostr:" + bech32id // nip19.toNostrUri()
@@ -379,6 +432,46 @@ function nextInput(e) {
}
}
async function checkuser(msg){
usernames = []
let profiles = await get_user_from_search(msg)
for (let profile of profiles){
usernames.push(profile)
}
}
async function get_user_from_search(name){
name = "\"name\":" + name
let profiles = []
let filter1 = new Filter().kind(0).search(name)
let evts = await dbclient.database.query([filter1])
//const profile_filter = new Filter().kind(0).search(name)
//let evts = await client.getEventsOf([profile_filter], 3)
for (const entry of evts){
try{
let contentjson = JSON.parse(entry.content)
//console.log(entry.content)
profiles.push({profile: contentjson, author: entry.author.toBech32(), createdAt: entry.createdAt});
}
catch(error){
console.log(error)
}
}
return profiles
}
defineProps({
msg: {
type: String,
@@ -386,6 +479,9 @@ defineProps({
},
})
</script>
@@ -399,13 +495,37 @@ defineProps({
Search the Nostr with Data Vending Machines</h2>
<h3>
<br>
<input class="c-Input" type="search" name="s" autofocus placeholder="Search..." v-model="message" @keyup.enter="send_search_request(message)" @keydown.enter="nextInput">
<button class="v-Button" @click="send_search_request(message)">Search the Nostr</button>
</h3>
<details class="collapse bg-base " className="advanced" >
<summary class="collapse-title font-thin bg">Advanced Options</summary>
<div class="collapse-content font-size-0" className="z-10" id="collapse-settings">
<div>
<h4 className="inline-flex flex-none font-thin">by: </h4>
<div className="inline-flex flex-none" style="width: 10px;"></div>
<input list="users" id="user" class="u-Input" style="margin-left: 10px" type="search" name="user" autofocus placeholder="npub..." v-model="fromuser" @input="checkuser(fromuser)">
<datalist id="users">
<option v-for="profile in usernames" :value="profile.author">
{{profile.profile.name + ' (' + profile.profile.nip05 + ')'}}
</option>
</datalist>
</div>
</div>
<div className="inline-flex flex-none" style="width: 20px;"></div>
<div>
<h4 className="inline-flex flex-none font-thin">from:</h4>
<div className="inline-flex flex-none" style="width: 10px;"></div>
@@ -418,10 +538,7 @@ defineProps({
<div className="inline-flex flex-none" style="width: 10px;"></div>
<VueDatePicker :teleport="true" :dark="true" position="left" className="bg-base-200 inline-flex flex-none" style="width: 220px;" v-model="dateto"></VueDatePicker>
</div>
</div>
</details>
</div>
<div class="max-w-5xl relative space-y-3">
<div class="grid grid-cols-1 gap-6">
@@ -465,6 +582,15 @@ defineProps({
}
.u-Input {
@apply bg-base-200 text-accent dark:bg-base-200 dark:text-white focus:ring-white border border-transparent px-3 py-1.5 text-sm leading-4 text-accent-content transition-colors duration-300 focus:ring-offset-2 focus:ring-offset-white dark:focus:ring-offset-gray-900;
width: 220px;
height: 35px;
}
.logo {
display: flex;
width:100%;
@@ -485,8 +611,11 @@ h4 {
.greetings h3 {
text-align: center;
}
@media (min-width: 1000px) {
.greetings h1,

View File

@@ -20,8 +20,8 @@
<div style="padding: 2px; text-align: left;" >
<a class="menusmall" :href="links.uri" target="_blank">Nostr Client</a>
<a class="menusmall" :href="links.njump" target="_blank">NJump</a>
<a class="menusmall" :href="links.highlighter" target="_blank">Highlighter</a>
<!-- <a class="menusmall":href="links.nostrudel" target="_blank">Nostrudel</a> -->
<!--<a class="menusmall" :href="links.highlighter" target="_blank">Highlighter</a> -->
<a class="menusmall":href="links.nostrudel" target="_blank">Nostrudel</a>
</div>
<!-- <p>{{content}}</p> -->
</template>

View File

@@ -1,250 +0,0 @@
[
{"name": "Albania"},
{"name": "Åland Islands"},
{"name": "Algeria"},
{"name": "American Samoa"},
{"name": "Andorra"},
{"name": "Angola"},
{"name": "Anguilla"},
{"name": "Antarctica"},
{"name": "Antigua and Barbuda"},
{"name": "Argentina"},
{"name": "Armenia"},
{"name": "Aruba"},
{"name": "Australia"},
{"name": "Austria"},
{"name": "Azerbaijan"},
{"name": "Bahamas (the)"},
{"name": "Bahrain"},
{"name": "Bangladesh"},
{"name": "Barbados"},
{"name": "Belarus"},
{"name": "Belgium"},
{"name": "Belize"},
{"name": "Benin"},
{"name": "Bermuda"},
{"name": "Bhutan"},
{"name": "Bolivia (Plurinational State of)"},
{"name": "Bonaire, Sint Eustatius and Saba"},
{"name": "Bosnia and Herzegovina"},
{"name": "Botswana"},
{"name": "Bouvet Island"},
{"name": "Brazil"},
{"name": "British Indian Ocean Territory (the)"},
{"name": "Brunei Darussalam"},
{"name": "Bulgaria"},
{"name": "Burkina Faso"},
{"name": "Burundi"},
{"name": "Cabo Verde"},
{"name": "Cambodia"},
{"name": "Cameroon"},
{"name": "Canada"},
{"name": "Cayman Islands (the)"},
{"name": "Central African Republic (the)"},
{"name": "Chad"},
{"name": "Chile"},
{"name": "China"},
{"name": "Christmas Island"},
{"name": "Cocos (Keeling) Islands (the)"},
{"name": "Colombia"},
{"name": "Comoros (the)"},
{"name": "Congo (the Democratic Republic of the)"},
{"name": "Congo (the)"},
{"name": "Cook Islands (the)"},
{"name": "Costa Rica"},
{"name": "Croatia"},
{"name": "Cuba"},
{"name": "Curaçao"},
{"name": "Cyprus"},
{"name": "Czechia"},
{"name": "Côte d'Ivoire"},
{"name": "Denmark"},
{"name": "Djibouti"},
{"name": "Dominica"},
{"name": "Dominican Republic (the)"},
{"name": "Ecuador"},
{"name": "Egypt"},
{"name": "El Salvador"},
{"name": "Equatorial Guinea"},
{"name": "Eritrea"},
{"name": "Estonia"},
{"name": "Eswatini"},
{"name": "Ethiopia"},
{"name": "Falkland Islands (the) [Malvinas]"},
{"name": "Faroe Islands (the)"},
{"name": "Fiji"},
{"name": "Finland"},
{"name": "France"},
{"name": "French Guiana"},
{"name": "French Polynesia"},
{"name": "French Southern Territories (the)"},
{"name": "Gabon"},
{"name": "Gambia (the)"},
{"name": "Georgia"},
{"name": "Germany"},
{"name": "Ghana"},
{"name": "Gibraltar"},
{"name": "Greece"},
{"name": "Greenland"},
{"name": "Grenada"},
{"name": "Guadeloupe"},
{"name": "Guam"},
{"name": "Guatemala"},
{"name": "Guernsey"},
{"name": "Guinea"},
{"name": "Guinea-Bissau"},
{"name": "Guyana"},
{"name": "Haiti"},
{"name": "Heard Island and McDonald Islands"},
{"name": "Holy See (the)"},
{"name": "Honduras"},
{"name": "Hong Kong"},
{"name": "Hungary"},
{"name": "Iceland"},
{"name": "India"},
{"name": "Indonesia"},
{"name": "Iran (Islamic Republic of)"},
{"name": "Iraq"},
{"name": "Ireland"},
{"name": "Isle of Man"},
{"name": "Israel"},
{"name": "Italy"},
{"name": "Jamaica"},
{"name": "Japan"},
{"name": "Jersey"},
{"name": "Jordan"},
{"name": "Kazakhstan"},
{"name": "Kenya"},
{"name": "Kiribati"},
{"name": "Korea (the Democratic People's Republic of)"},
{"name": "Korea (the Republic of)"},
{"name": "Kuwait"},
{"name": "Kyrgyzstan"},
{"name": "Lao People's Democratic Republic (the)"},
{"name": "Latvia"},
{"name": "Lebanon"},
{"name": "Lesotho"},
{"name": "Liberia"},
{"name": "Libya"},
{"name": "Liechtenstein"},
{"name": "Lithuania"},
{"name": "Luxembourg"},
{"name": "Macao"},
{"name": "Madagascar"},
{"name": "Malawi"},
{"name": "Malaysia"},
{"name": "Maldives"},
{"name": "Mali"},
{"name": "Malta"},
{"name": "Marshall Islands (the)"},
{"name": "Martinique"},
{"name": "Mauritania"},
{"name": "Mauritius"},
{"name": "Mayotte"},
{"name": "Mexico"},
{"name": "Micronesia (Federated States of)"},
{"name": "Moldova (the Republic of)"},
{"name": "Monaco"},
{"name": "Mongolia"},
{"name": "Montenegro"},
{"name": "Montserrat"},
{"name": "Morocco"},
{"name": "Mozambique"},
{"name": "Myanmar"},
{"name": "Namibia"},
{"name": "Nauru"},
{"name": "Nepal"},
{"name": "Netherlands (the)"},
{"name": "New Caledonia"},
{"name": "New Zealand"},
{"name": "Nicaragua"},
{"name": "Niger (the)"},
{"name": "Nigeria"},
{"name": "Niue"},
{"name": "Norfolk Island"},
{"name": "Northern Mariana Islands (the)"},
{"name": "Norway"},
{"name": "Oman"},
{"name": "Pakistan"},
{"name": "Palau"},
{"name": "Palestine, State of"},
{"name": "Panama"},
{"name": "Papua New Guinea"},
{"name": "Paraguay"},
{"name": "Peru"},
{"name": "Philippines (the)"},
{"name": "Pitcairn"},
{"name": "Poland"},
{"name": "Portugal"},
{"name": "Puerto Rico"},
{"name": "Qatar"},
{"name": "Republic of North Macedonia"},
{"name": "Romania"},
{"name": "Russian Federation (the)"},
{"name": "Rwanda"},
{"name": "Réunion"},
{"name": "Saint Barthélemy"},
{"name": "Saint Helena, Ascension and Tristan da Cunha"},
{"name": "Saint Kitts and Nevis"},
{"name": "Saint Lucia"},
{"name": "Saint Martin (French part)"},
{"name": "Saint Pierre and Miquelon"},
{"name": "Saint Vincent and the Grenadines"},
{"name": "Samoa"},
{"name": "San Marino"},
{"name": "Sao Tome and Principe"},
{"name": "Saudi Arabia"},
{"name": "Senegal"},
{"name": "Serbia"},
{"name": "Seychelles"},
{"name": "Sierra Leone"},
{"name": "Singapore"},
{"name": "Sint Maarten (Dutch part)"},
{"name": "Slovakia"},
{"name": "Slovenia"},
{"name": "Solomon Islands"},
{"name": "Somalia"},
{"name": "South Africa"},
{"name": "South Georgia and the South Sandwich Islands"},
{"name": "South Sudan"},
{"name": "Spain"},
{"name": "Sri Lanka"},
{"name": "Sudan (the)"},
{"name": "Suriname"},
{"name": "Svalbard and Jan Mayen"},
{"name": "Sweden"},
{"name": "Switzerland"},
{"name": "Syrian Arab Republic"},
{"name": "Taiwan (Province of China)"},
{"name": "Tajikistan"},
{"name": "Tanzania, United Republic of"},
{"name": "Thailand"},
{"name": "Timor-Leste"},
{"name": "Togo"},
{"name": "Tokelau"},
{"name": "Tonga"},
{"name": "Trinidad and Tobago"},
{"name": "Tunisia"},
{"name": "Turkey"},
{"name": "Turkmenistan"},
{"name": "Turks and Caicos Islands (the)"},
{"name": "Tuvalu"},
{"name": "Uganda"},
{"name": "Ukraine"},
{"name": "United Arab Emirates (the)"},
{"name": "United Kingdom of Great Britain and Northern Ireland (the)"},
{"name": "United States Minor Outlying Islands (the)"},
{"name": "United States of America (the)"},
{"name": "Uruguay"},
{"name": "Uzbekistan"},
{"name": "Vanuatu"},
{"name": "Venezuela (Bolivarian Republic of)"},
{"name": "Viet Nam"},
{"name": "Virgin Islands (British)"},
{"name": "Virgin Islands (U.S.)"},
{"name": "Wallis and Futuna"},
{"name": "Western Sahara"},
{"name": "Yemen"},
{"name": "Zambia"},
{"name": "Zimbabwe", "code": "ZW"}
]

View File

@@ -1,4 +0,0 @@
[
{"id": "1c986b929f61d7a696719c9f92d41e2163e82c0fcdf30779a09f9b70886ad59c", "name": "Noogle: Latest" },
{"id": "d70aea7efa004887514b0c6b53d0448029303989c6fc33ba37f2315ca77a4170", "name": "Noogle: One year ago"}
]