Sign events from NIP-07 ext
This commit is contained in:
parent
987ef0ed7b
commit
523d1951fa
@ -3,6 +3,9 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||||
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
"@noble/secp256k1": "^1.7.0",
|
"@noble/secp256k1": "^1.7.0",
|
||||||
"@reduxjs/toolkit": "^1.9.1",
|
"@reduxjs/toolkit": "^1.9.1",
|
||||||
"bech32": "^2.0.0",
|
"bech32": "^2.0.0",
|
||||||
|
@ -39,12 +39,17 @@ code {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn:hover {
|
.btn:hover {
|
||||||
background-color: #333;
|
background-color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-sm {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
input[type="text"], input[type="password"] {
|
input[type="text"], input[type="password"] {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
@ -93,6 +98,7 @@ div.form-group {
|
|||||||
|
|
||||||
div.form-group > div {
|
div.form-group > div {
|
||||||
padding: 3px 5px;
|
padding: 3px 5px;
|
||||||
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.form-group > div:first-child {
|
div.form-group > div:first-child {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { setPrivateKey, setPublicKey } from "../state/Login";
|
import { setPrivateKey, setNip07PubKey } from "../state/Login";
|
||||||
import * as secp from '@noble/secp256k1';
|
import * as secp from '@noble/secp256k1';
|
||||||
import { bech32 } from "bech32";
|
import { bech32 } from "bech32";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
@ -32,12 +32,11 @@ export default function LoginPage() {
|
|||||||
|
|
||||||
async function doNip07Login() {
|
async function doNip07Login() {
|
||||||
let pubKey = await window.nostr.getPublicKey();
|
let pubKey = await window.nostr.getPublicKey();
|
||||||
dispatch(setPublicKey(pubKey));
|
dispatch(setNip07PubKey(pubKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
function altLogins() {
|
function altLogins() {
|
||||||
let nip07 = 'nostr' in window;
|
let nip07 = 'nostr' in window;
|
||||||
|
|
||||||
if (!nip07) {
|
if (!nip07) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.profile .avatar {
|
.profile .avatar {
|
||||||
width: 256px;
|
width: 128px;
|
||||||
height: 256px;
|
height: 128px;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
@ -26,4 +26,15 @@
|
|||||||
|
|
||||||
.profile .avatar .edit:hover {
|
.profile .avatar .edit:hover {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media(max-width: 720px) {
|
||||||
|
.profile {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.profile > div:last-child {
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,6 +8,9 @@ import Nostrich from "../nostrich.jpg";
|
|||||||
import useEventPublisher from "./feed/EventPublisher";
|
import useEventPublisher from "./feed/EventPublisher";
|
||||||
import useTimelineFeed from "./feed/TimelineFeed";
|
import useTimelineFeed from "./feed/TimelineFeed";
|
||||||
import Note from "../element/Note";
|
import Note from "../element/Note";
|
||||||
|
import { bech32 } from "bech32";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { faQrcode } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
export default function ProfilePage() {
|
export default function ProfilePage() {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@ -37,6 +40,23 @@ export default function ProfilePage() {
|
|||||||
}
|
}
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// some clients incorrectly set this to LNURL service, patch this
|
||||||
|
if (lud16.toLowerCase().startsWith("lnurl")) {
|
||||||
|
let decoded = bech32.decode(lud16, 1000);
|
||||||
|
let url = new TextDecoder().decode(Uint8Array.from(bech32.fromWords(decoded.words)));
|
||||||
|
if (url.startsWith("http")) {
|
||||||
|
let parsedUri = new URL(url);
|
||||||
|
// is lightning address
|
||||||
|
if (parsedUri.pathname.startsWith("/.well-known/lnurlp/")) {
|
||||||
|
let pathParts = parsedUri.pathname.split('/');
|
||||||
|
let username = pathParts[pathParts.length - 1];
|
||||||
|
setLud16(`${username}@${parsedUri.hostname}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [lud16]);
|
||||||
|
|
||||||
async function saveProfile() {
|
async function saveProfile() {
|
||||||
let ev = await publisher.metadata({
|
let ev = await publisher.metadata({
|
||||||
name,
|
name,
|
||||||
@ -79,7 +99,7 @@ export default function ProfilePage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<div>Lightning Address:</div>
|
<div>LN Address:</div>
|
||||||
<div>
|
<div>
|
||||||
<input type="text" value={lud16} onChange={(e) => setLud16(e.target.value)} />
|
<input type="text" value={lud16} onChange={(e) => setLud16(e.target.value)} />
|
||||||
</div>
|
</div>
|
||||||
@ -116,18 +136,23 @@ export default function ProfilePage() {
|
|||||||
{website}
|
{website}
|
||||||
</div>
|
</div>
|
||||||
</div> : null}
|
</div> : null}
|
||||||
<div className="form-group">
|
{nip05 ?
|
||||||
<div>NIP-05:</div>
|
<div className="form-group">
|
||||||
<div>
|
<div>NIP-05:</div>
|
||||||
{nip05}
|
<div>
|
||||||
</div>
|
{nip05}
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group">
|
</div> : null}
|
||||||
<div>Lightning Address:</div>
|
{lud16 ?
|
||||||
<div>
|
<div className="form-group">
|
||||||
{lud16}
|
<div>LN Address:</div>
|
||||||
</div>
|
<div>
|
||||||
</div>
|
{lud16}
|
||||||
|
<div className="btn btn-sm" onClick={() => { }}>
|
||||||
|
<FontAwesomeIcon icon={faQrcode} size="lg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> : null}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -135,15 +160,13 @@ export default function ProfilePage() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="profile">
|
<div className="profile">
|
||||||
<div>
|
<div style={{ backgroundImage: `url(${picture})` }} className="avatar">
|
||||||
<div style={{ backgroundImage: `url(${picture})` }} className="avatar">
|
{isMe ?
|
||||||
{isMe ?
|
<div className="edit">
|
||||||
<div className="edit">
|
<div>Edit</div>
|
||||||
<div>Edit</div>
|
</div>
|
||||||
</div>
|
: null
|
||||||
: null
|
}
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{isMe ? editor() : details()}
|
{isMe ? editor() : details()}
|
||||||
|
@ -9,6 +9,26 @@ export default function useEventPublisher() {
|
|||||||
const system = useContext(NostrContext);
|
const system = useContext(NostrContext);
|
||||||
const pubKey = useSelector(s => s.login.publicKey);
|
const pubKey = useSelector(s => s.login.publicKey);
|
||||||
const privKey = useSelector(s => s.login.privateKey);
|
const privKey = useSelector(s => s.login.privateKey);
|
||||||
|
const nip07 = useSelector(s => s.login.nip07);
|
||||||
|
const hasNip07 = 'nostr' in window;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Event} ev
|
||||||
|
* @param {*} privKey
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function signEvent(ev, privKey) {
|
||||||
|
if(nip07 === true && hasNip07) {
|
||||||
|
ev.Id = await ev.CreateId();
|
||||||
|
let tmpEv = await window.nostr.signEvent(ev.ToObject());
|
||||||
|
console.log(tmpEv);
|
||||||
|
return Event.FromObject(tmpEv);
|
||||||
|
} else {
|
||||||
|
await ev.Sign(privKey);
|
||||||
|
}
|
||||||
|
return ev;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
broadcast: (ev) => {
|
broadcast: (ev) => {
|
||||||
@ -19,8 +39,7 @@ export default function useEventPublisher() {
|
|||||||
let ev = Event.ForPubKey(pubKey);
|
let ev = Event.ForPubKey(pubKey);
|
||||||
ev.Kind = EventKind.SetMetadata;
|
ev.Kind = EventKind.SetMetadata;
|
||||||
ev.Content = JSON.stringify(obj);
|
ev.Content = JSON.stringify(obj);
|
||||||
await ev.Sign(privKey);
|
return await signEvent(ev, privKey);
|
||||||
return ev;
|
|
||||||
},
|
},
|
||||||
note: async (msg) => {
|
note: async (msg) => {
|
||||||
if(typeof msg !== "string") {
|
if(typeof msg !== "string") {
|
||||||
@ -29,8 +48,7 @@ export default function useEventPublisher() {
|
|||||||
let ev = Event.ForPubKey(pubKey);
|
let ev = Event.ForPubKey(pubKey);
|
||||||
ev.Kind = EventKind.TextNote;
|
ev.Kind = EventKind.TextNote;
|
||||||
ev.Content = msg;
|
ev.Content = msg;
|
||||||
await ev.Sign(privKey);
|
return await signEvent(ev, privKey);
|
||||||
return ev;
|
|
||||||
},
|
},
|
||||||
like: async (evRef) => {
|
like: async (evRef) => {
|
||||||
let ev = Event.ForPubKey(pubKey);
|
let ev = Event.ForPubKey(pubKey);
|
||||||
@ -38,8 +56,7 @@ export default function useEventPublisher() {
|
|||||||
ev.Content = "+";
|
ev.Content = "+";
|
||||||
ev.Tags.push(new Tag(["e", evRef.Id], 0));
|
ev.Tags.push(new Tag(["e", evRef.Id], 0));
|
||||||
ev.Tags.push(new Tag(["p", evRef.PubKey], 1));
|
ev.Tags.push(new Tag(["p", evRef.PubKey], 1));
|
||||||
await ev.Sign(privKey);
|
return await signEvent(ev, privKey);
|
||||||
return ev;
|
|
||||||
},
|
},
|
||||||
dislike: async (evRef) => {
|
dislike: async (evRef) => {
|
||||||
let ev = Event.ForPubKey(pubKey);
|
let ev = Event.ForPubKey(pubKey);
|
||||||
@ -47,8 +64,7 @@ export default function useEventPublisher() {
|
|||||||
ev.Content = "-";
|
ev.Content = "-";
|
||||||
ev.Tags.push(new Tag(["e", evRef.Id], 0));
|
ev.Tags.push(new Tag(["e", evRef.Id], 0));
|
||||||
ev.Tags.push(new Tag(["p", evRef.PubKey], 1));
|
ev.Tags.push(new Tag(["p", evRef.PubKey], 1));
|
||||||
await ev.Sign(privKey);
|
return await signEvent(ev, privKey);
|
||||||
return ev;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,7 +24,12 @@ const LoginSlice = createSlice({
|
|||||||
/**
|
/**
|
||||||
* A list of pubkeys this user follows
|
* A list of pubkeys this user follows
|
||||||
*/
|
*/
|
||||||
follows: []
|
follows: [],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login keys are managed by extension
|
||||||
|
*/
|
||||||
|
nip07: false,
|
||||||
},
|
},
|
||||||
reducers: {
|
reducers: {
|
||||||
init: (state) => {
|
init: (state) => {
|
||||||
@ -47,6 +52,10 @@ const LoginSlice = createSlice({
|
|||||||
setPublicKey: (state, action) => {
|
setPublicKey: (state, action) => {
|
||||||
state.publicKey = action.payload;
|
state.publicKey = action.payload;
|
||||||
},
|
},
|
||||||
|
setNip07PubKey: (state, action) => {
|
||||||
|
state.publicKey = action.payload;
|
||||||
|
state.nip07 = true;
|
||||||
|
},
|
||||||
setRelays: (state, action) => {
|
setRelays: (state, action) => {
|
||||||
state.relays = action.payload;
|
state.relays = action.payload;
|
||||||
},
|
},
|
||||||
@ -60,5 +69,5 @@ const LoginSlice = createSlice({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const { init, setPrivateKey, setPublicKey, setRelays, setFollows, logout } = LoginSlice.actions;
|
export const { init, setPrivateKey, setPublicKey, setNip07PubKey, setRelays, setFollows, logout } = LoginSlice.actions;
|
||||||
export const reducer = LoginSlice.reducer;
|
export const reducer = LoginSlice.reducer;
|
26
yarn.lock
26
yarn.lock
@ -1200,6 +1200,32 @@
|
|||||||
minimatch "^3.1.2"
|
minimatch "^3.1.2"
|
||||||
strip-json-comments "^3.1.1"
|
strip-json-comments "^3.1.1"
|
||||||
|
|
||||||
|
"@fortawesome/fontawesome-common-types@6.2.1":
|
||||||
|
version "6.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz#411e02a820744d3f7e0d8d9df9d82b471beaa073"
|
||||||
|
integrity sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==
|
||||||
|
|
||||||
|
"@fortawesome/fontawesome-svg-core@^6.2.1":
|
||||||
|
version "6.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.1.tgz#e87e905e444b5e7b715af09b64d27b53d4c8f9d9"
|
||||||
|
integrity sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA==
|
||||||
|
dependencies:
|
||||||
|
"@fortawesome/fontawesome-common-types" "6.2.1"
|
||||||
|
|
||||||
|
"@fortawesome/free-solid-svg-icons@^6.2.1":
|
||||||
|
version "6.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.1.tgz#2290ea5adcf1537cbd0c43de6feb38af02141d27"
|
||||||
|
integrity sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==
|
||||||
|
dependencies:
|
||||||
|
"@fortawesome/fontawesome-common-types" "6.2.1"
|
||||||
|
|
||||||
|
"@fortawesome/react-fontawesome@^0.2.0":
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz#d90dd8a9211830b4e3c08e94b63a0ba7291ddcf4"
|
||||||
|
integrity sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==
|
||||||
|
dependencies:
|
||||||
|
prop-types "^15.8.1"
|
||||||
|
|
||||||
"@humanwhocodes/config-array@^0.11.6":
|
"@humanwhocodes/config-array@^0.11.6":
|
||||||
version "0.11.8"
|
version "0.11.8"
|
||||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"
|
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user