-
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #95 from HiveTalk/room_owners
Check Room owners and initial NIP98 [Work in Progress]
- Loading branch information
Showing
7 changed files
with
600 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
HIVETALK_URL=<https://hivetalk.org> | ||
SUPABASE_URL=<supabase_url> | ||
SUPABASE_ANON_KEY=<supabase_anon_key> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// THIS IS SAMPLE CODE ONLY, DOES NOT WORK IN PRODUCTION | ||
|
||
// <script src="https://unpkg.com/nostr-tools/lib/nostr.bundle.js"></script> | ||
|
||
// const { signEvent } = NostrTools; | ||
|
||
// var loggedIn = false; | ||
// let pubkey = ""; | ||
// let username = ""; | ||
// let avatarURL = "https://cdn-icons-png.flaticon.com/512/149/149071.png"; | ||
|
||
// function loadUser() { | ||
// if (window.nostr) { | ||
// window.nostr.getPublicKey().then(function (pubkey) { | ||
// if (pubkey) { | ||
// loggedIn = true | ||
// console.log("fetched pubkey", pubkey) | ||
// } | ||
// }).catch((err) => { | ||
// console.log("LoadUser Err", err); | ||
// console.log("logoff section") | ||
// loggedIn = false | ||
// }); | ||
// } | ||
// } | ||
|
||
|
||
// class NostrAuthClient { | ||
// /** | ||
// * Construct a new NostrAuthClient instance. | ||
// * @param {string} pubkey - Nostr public key of the user. | ||
// */ | ||
// constructor(pubkey) { | ||
// this.publicKey = pubkey; | ||
// } | ||
|
||
// // Generate a Nostr event for HTTP authentication | ||
// async createAuthEvent(url, method, payload = null) { | ||
// const tags = [ | ||
// ['u', url], | ||
// ['method', method.toUpperCase()] | ||
// ]; | ||
|
||
// // If payload exists, add its SHA256 hash | ||
// if (payload) { | ||
// const payloadHash = await this.sha256(payload); | ||
// tags.push(['payload', payloadHash]); | ||
// } | ||
|
||
// const event = { | ||
// kind: 27235, | ||
// created_at: Math.floor(Date.now() / 1000), | ||
// tags: tags, | ||
// content: '', | ||
// pubkey: this.publicKey | ||
// }; | ||
// console.log('event: ', event) | ||
|
||
// // Calculate event ID | ||
// event.id = await this.calculateId(event); | ||
|
||
// // Sign the event | ||
// event.sig = await window.nostr.signEvent(event); | ||
// return event; | ||
// } | ||
|
||
// // Utility functions for cryptographic operations | ||
// async sha256(message) { | ||
// const msgBuffer = new TextEncoder().encode(message); | ||
// const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer); | ||
// const hashArray = Array.from(new Uint8Array(hashBuffer)); | ||
// return hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); | ||
// } | ||
|
||
// async calculateId(event) { | ||
// const eventData = JSON.stringify([ | ||
// 0, | ||
// event.pubkey, | ||
// event.created_at, | ||
// event.kind, | ||
// event.tags, | ||
// event.content | ||
// ]); | ||
// return await this.sha256(eventData); | ||
// } | ||
// } | ||
|
||
// // Make an authenticated request | ||
// async function fetchWithNostrAuth(url, options = {}) { | ||
// const method = options.method || 'GET'; | ||
// const payload = options.body || null; | ||
|
||
// const client = new NostrAuthClient(pubkey); | ||
// const authEvent = await client.createAuthEvent(url, method, payload); | ||
|
||
// // Convert event to base64 | ||
// const authHeader = 'Nostr ' + btoa(JSON.stringify(authEvent)); | ||
|
||
// // Add auth header to request | ||
// const headers = new Headers(options.headers || {}); | ||
// headers.set('Authorization', authHeader); | ||
|
||
// // Make the request | ||
// return fetch(url, { | ||
// ...options, | ||
// headers | ||
// }); | ||
// } | ||
|
||
// // Helper function to get base domain/host with port if needed | ||
// function getBaseUrl() { | ||
// // Get the full host (includes port if it exists) | ||
// const host = window.location.host; | ||
// // Get the protocol (http: or https:) | ||
// const protocol = window.location.protocol; | ||
// // Combine them | ||
// return `${protocol}//${host}`; | ||
// } | ||
|
||
// async function authNIP98() { | ||
|
||
// const roomName = "TestRoom"; | ||
// const preferredRelays = ['wss://hivetalk.nostr1.com'] | ||
// const isModerator = true; | ||
|
||
// try { | ||
// const baseUrl = getBaseUrl(); | ||
// fetchWithNostrAuth(`${baseUrl}/api/auth`, { | ||
// method: 'POST', | ||
// headers: { | ||
// 'Content-Type': 'application/json', | ||
// }, | ||
// body: JSON.stringify({ | ||
// room: roomName, | ||
// username: username, | ||
// avatarURL: avatarURL, | ||
// relays: preferredRelays, | ||
// isPresenter: isModerator, | ||
// }), | ||
// }).then(response => { | ||
// console.log('response', response.status) | ||
// if (response.status === 302) { | ||
// console.log("response status is 302") // Get the redirect URL from the response | ||
// const data = response.json(); | ||
// window.location.href = data.redirectUrl; | ||
// } else if (response.ok) { | ||
// console.log("response.ok", response.ok) | ||
// return response.json(); | ||
// } else { | ||
// console.error('Login failed'); | ||
// } | ||
// }).then(data => { | ||
// console.log('auth success: ', data); | ||
// document.getElementById('protected').innerHTML = data['message']; | ||
// }) | ||
|
||
// } catch (error) { | ||
// console.error('Error:', error); | ||
// document.getElementById('protected').innerHTML = error; | ||
// } | ||
// } | ||
|
||
|
||
// loadUser(); | ||
// authNIP98(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
// THIS IS SAMPLE CODE ONLY, DOES NOT WORK IN PRODUCTION | ||
|
||
|
||
// const express = require('express') | ||
// const cors = require('cors') | ||
// const { verifyEvent } = require('nostr-tools'); | ||
|
||
// class NostrAuthMiddleware { | ||
// constructor(options = {}) { | ||
// this.timeWindow = options.timeWindow || 60; // seconds | ||
// } | ||
|
||
// // Middleware function for Express | ||
// middleware() { | ||
// return async (req, res, next) => { | ||
// try { | ||
// const isValid = await this.validateRequest(req); | ||
// console.log("isValid : ", isValid) | ||
// if (!isValid) { | ||
// return res.status(401).json({ | ||
// error: 'Invalid Nostr authentication' | ||
// }); | ||
// } | ||
// next(); | ||
// } catch (error) { | ||
// console.error('Nostr auth error:', error); | ||
// res.status(401).json({ | ||
// error: 'Authentication failed' | ||
// }); | ||
// } | ||
// }; | ||
// } | ||
|
||
// async validateRequest(req) { | ||
// // Extract the Nostr event from Authorization header | ||
// const authHeader = req.headers.authorization; | ||
// console.log("validate request auth header: ", authHeader) | ||
|
||
// if (!authHeader?.startsWith('Nostr ')) { | ||
// return false; | ||
// } | ||
|
||
// try { | ||
// // Decode the base64 event | ||
// const eventStr = Buffer.from(authHeader.slice(6), 'base64').toString(); | ||
// const event = JSON.parse(eventStr); | ||
|
||
// console.log("eventStr: ", eventStr) | ||
// console.log('event decoded: ', event) | ||
|
||
// // Validate the event | ||
// return await this.validateEvent(event.sig, req); | ||
// } catch (error) { | ||
// console.error('Error parsing auth event:', error); | ||
// return false; | ||
// } | ||
// } | ||
|
||
// async validateEvent(event, req) { | ||
// // 1. Check kind | ||
// if (event.kind !== 27235) { | ||
// return false; | ||
// } | ||
// console.log("check kind") | ||
|
||
// // 2. Check timestamp | ||
// const now = Math.floor(Date.now() / 1000); | ||
// if (Math.abs(now - event.created_at) > this.timeWindow) { | ||
// return false; | ||
// } | ||
// console.log("check timestamp") | ||
|
||
// // 3. Check URL | ||
// const urlTag = event.tags.find(tag => tag[0] === 'u'); | ||
|
||
// console.log('urltag: ', urlTag[1]) | ||
// console.log('full url: ', this.getFullUrl(req)) | ||
|
||
// if (!urlTag || urlTag[1] !== this.getFullUrl(req)) { | ||
// return false; | ||
// } | ||
// console.log("check URL") | ||
|
||
// // 4. Check method | ||
// const methodTag = event.tags.find(tag => tag[0] === 'method'); | ||
// if (!methodTag || methodTag[1] !== req.method) { | ||
// return false; | ||
// } | ||
// console.log("check method") | ||
|
||
// // 5. Check payload hash if present | ||
// if (req.body && Object.keys(req.body).length > 0) { | ||
// const payloadTag = event.tags.find(tag => tag[0] === 'payload'); | ||
// if (payloadTag) { | ||
// const bodyHash = await this.sha256(JSON.stringify(req.body)); | ||
// if (bodyHash !== payloadTag[1]) { | ||
// return false; | ||
// } | ||
// } | ||
// } | ||
// console.log("check payload hash if present") | ||
|
||
// // 6. Verify event signature | ||
// return await this.verifySignature(event); | ||
// } | ||
|
||
// // Utility functions | ||
// getFullUrl(req) { | ||
// // return `${req.protocol}://${req.get('host')}${req.originalUrl}`; | ||
// return `https://${req.get('host')}${req.originalUrl}`; | ||
// } | ||
|
||
// async sha256(message) { | ||
// return crypto | ||
// .createHash('sha256') | ||
// .update(message) | ||
// .digest('hex'); | ||
// } | ||
|
||
// async calculateEventId(event) { | ||
// // Serialize the event data according to NIP-01 | ||
// const serialized = JSON.stringify([ | ||
// 0, // Reserved for future use | ||
// event.pubkey, | ||
// event.created_at, | ||
// event.kind, | ||
// event.tags, | ||
// event.content | ||
// ]); | ||
|
||
// // Calculate SHA256 hash | ||
// return await this.sha256(serialized); | ||
// } | ||
|
||
// async verifySignature(event) { | ||
// let isGood = verifyEvent(event) | ||
// console.log("Verify Event", isGood) | ||
// return isGood | ||
// } | ||
|
||
// } | ||
|
||
// const app = express(); | ||
// const nostrAuth = new NostrAuthMiddleware(); | ||
// app.use(express.json({ limit: '50mb' })); // Increase the limit if necessary | ||
|
||
// app.use( | ||
// cors({ | ||
// origin: '*', | ||
// }) | ||
// ) | ||
|
||
// app.get('/api', (req, res) => { | ||
// res.setHeader('Content-Type', 'text/html') | ||
// res.setHeader('Cache-Control', 's-max-age=1, stale-while-revalidate') | ||
// res.send('hello world') | ||
// }) | ||
|
||
// app.post('/api/auth', | ||
// nostrAuth.middleware(), | ||
// (req, res) => { | ||
// try { | ||
// // Accessing the JSON body sent by the client | ||
// const { room, username, avatarURL, relays, isPresenter } = req.body; | ||
// console.log('Room:', room); | ||
// console.log('Username:', username); | ||
// console.log('Avatar URL:', avatarURL); | ||
// console.log('Relays:', relays); | ||
// console.log('isPresenter', isPresenter); | ||
|
||
// // TODO: Redirect to hivetalk room give above info, correctly | ||
// res.status(200).json({ message: 'Authentication successful'}); | ||
|
||
// } catch (error) { | ||
// console.log("authentication failed") | ||
// res.status(401).json({ error: 'Authentication failed' }); | ||
// } | ||
// } | ||
// ); | ||
|
||
// module.exports = app; |
Oops, something went wrong.