amark on master
prepare to sync gun lib unbuild… (compare)
amark on master
ok ack + webrtc Merge branch 'master' of http:/… bump (ok ack + webrtc) @Draeder… (compare)
amark on master
websocket ../index to ./index (… (compare)
hey amazing ppl - I'm building a nextjs app, and getting the following err thrown when using getServerSideProps - interestingly, neither page is using any gun functionality.
ERROR Error: Cannot find module './lib/text-encoding'
Require stack:
- /var/task/node_modules/gun/sea.js
has anyone run into this, or is a next/gun wizard who'd be willing to take a peak at my code?
@amark so the problem seems to be docker. My setup was:
ufw firewall
- docker-compose
- nginx proxy manager docker container
- gundb node.js docker container
I could not debug the issue at all. All realtime updates are fine but unable to receive old data from the client side. I put logs on the node.js server to make sure it does have the data and it does. Connections also look fine. I have no idea what's wrong. It feels like when I spin up the docker instance and connect remote clients to it, the clients connect to a different gun instance that has no record of old file, which is so weird.
I changed the setup to:
ufw firewall
- docker-compose
- nginx proxy manager docker container
- gundb node.js run using pm2 instead of inside a docker container
And now the issue seems to be solved. I have some other pressing tasks right now so cannot really play around more for the time being, but it would be great if I could solve this using the docker container (docker compose). By doing this I could avoid node dependencies on the host machine. It would also be easier to maintain the server.
@despiegk i had the same problem i wrote some proxy types but its bit hacky and i dont use all functions from api so i didnt need full interface also i restricted their usage to end on first on() or once()
import Gun, { SEA } from "gun";
import 'gun/axe'
import 'gun/sea'
import { IGunConstructorOptions } from "gun/types/options";
import { AckCallback } from "gun/types/types";
type AuthArgs = [username: string, password: string, callback: (data: { err?: string }) => any] | [ pair :SEAPair, callback: (data: { err?: string }) => any]
export interface GunUser<T> {
is?: undefined
recall: (opt?: { sessionStorage: typeof sessionStorage }) => GunUser<T> |AuthenticatedGunUser<T>
auth: (...t: AuthArgs) => GunUser<T> |AuthenticatedGunUser<T>
create: (...t: AuthArgs) => GunUser<T> |AuthenticatedGunUser<T>
}
export interface AuthenticatedGunUser<T >{
is: {
alias: string | SEAPair
epub: string
pub: string
}
get: <TKey extends keyof T>(name: TKey) => AuthenticatedGunUserTree<T, TKey> & Promise<T[TKey]>
leave: () => void
}
type AuthenticatedGunUserTree<T , TKey extends keyof T> = AuthenticatedGunUser<T[TKey]> & GunTree<T,TKey>;
interface GunGet<T> {
get: <TKey extends keyof T>(name: TKey) => GunTree<T ,TKey> & GunGet<T[TKey]> &Promise<T[TKey]>
}
type GunTree<T , TKey extends keyof T> = {
on: (callback:(state:T[TKey], key: TKey) => any) => { off: ()=> void }
once: (callback: (state:T[TKey], key: TKey) => any) => void
put: (state: T[TKey], callback?: AckCallback, options ?: {opt ?: { cert ?: string}} ) => void,
set: (state: T[TKey]) => void,
map: (match?: any) => AuthenticatedGunUserTree<T[TKey], keyof T[TKey]>
}
export function isUserAuthenticated <T>(user : GunUser<T> |AuthenticatedGunUser<T>): user is AuthenticatedGunUser<T>{
return !!user.is
}
interface GunDefinition {
user: <T>() => GunUser<T> | AuthenticatedGunUser<T>,
get: <T,TKey extends keyof T>(name: TKey) => GunTree<T ,TKey> & GunGet<T[TKey]> &Promise<T[TKey]>,
on: (eventName: 'auth', callback: () => any) => { off: ()=> void },
}
const TypedGun = Gun as any as {
(options?: string | string[] | IGunConstructorOptions): GunDefinition;
new (options?: string | string[] | IGunConstructorOptions): GunDefinition;
}
export interface SEAPair{
epriv: string
epub: string
priv: string
pub: string
}
type Authority = SEAPair
export const TypedSEA = SEA as any as {
secret: (epubKey: string, pair: SEAPair) => Promise<string>
pair: () => Promise<SEAPair>
sign: (data:any, pair: SEAPair) => Promise<string>
verify: <T>(data: string, pair: SEAPair | string) => Promise<T | undefined>
encrypt: (data:any, pair: SEAPair | string) => Promise<string>
decrypt: <T>(data:string, pair: SEAPair | string) => Promise<T| undefined>
certify: (user : string | string[]| {pub:string} | {pub:string}[], policies: any, pair: Authority, callback: (cert:string) => any, opt?: { blacklist?: string, expiry?:number }) => Promise<string>
}
just use TypedGun or TypedSEA
@amark. Please implement this Forum as multiple threads initiated by each user, not a single thread currently. It is just a mess. Shift this Forum to reddit, and leave gitter?
@amark how can I change the username or alias for gun.user()?
@amark. I want to implement state management on the Clent-side using gundb. I want to expose only a subset of nodes e.g. gun.get("sessionid") on Client-side. I searched a lot, but still have doubts what if client-side hacking may access full gun graph network using XSS/code-injection. What security measures should I take? Is including SEA library enough security measure?
@amark. I am implementing gundb for a production grade app.
// Clear out localstorage to give Gun a fresh start on every load
localStorage.clear()
// Import Gun as a dependency
import Gun from 'gun'
/
var gun = Gun();
/
const server = require('http').createServer().listen(8080);
const gun = Gun({web: server});
var items = gun.get('items');
$('form').on('submit', function(e){
e.preventDefault();
items.set($('input').val());
$('input').val("");
})
items.map().on(function(item, id){
var li = $('#' + id).get(0) || $('<li>').attr('id', id).appendTo('ul');
if(item){
$(li).text(item);
} else {
$(li).hide();
}
})
Hi,
Sorry if this is a silly question, but I've been going over the docs today and I don't quite understand conceptually how the scopes work. So I think I get how user contexts work with storing data like in the following snippet:
$('#said').on('submit', function(e){
e.preventDefault();
if(!user.is){ return }
user.get('said').set($('#say').val());
$('#say').val("");
});
where the get/set/map methods apply to that users space, but if any endpoint can set data into the global space doesn't that mean that the global data set can be flooded? or is there some logic in the relay servers that I'm not understanding that prevents arbitrary data from being ingested and stored?
thoughts on how i would achieve key pair rotation for users created with user.create
? reading the docs, it seems that gun users are essentially key pairs generated with SEA.pair()
. does this mean i need to keep my own way of mapping usernames/alias to a pair, something like:
SEA.pair(({pair}) => {
gun.get('users').
('@some_username').get('activePublicKey').put(pair.pub)
// use `.activePublicKey` to encrypt, certify, etc.
})
or will (nope that would return a "user already exists" error.) gun.user().create(oldUsername, oldPaassphrase)
automatically update the keys?
gun.get('@newAliasYouWant').set(user)
(where user
is logged in)local = GUN(); gun = GUN(peers);
. Does this help?async
, this would be very mysterious if true. Can you replicate?