JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://unpkg.com/bsv@1.5.3/bsv.min.js"></script>
<script src="https://unpkg.com/bsv@1.5.3/bsv-message.min.js"></script>

JavaScript

const Buffer = bsv.deps.Buffer;
const Address = bsv.Address;
const Signature = bsv.crypto.Signature;
const ECDSA = bsv.crypto.ECDSA;
const Script = bsv.Script;
const sha256 = bsv.crypto.Hash.sha256;

/*
Accepts the hex encoded format of a Twetch post OP_RETURN output and returns the public key of the signer.
*/

function recoverPublicKey(hex){
		//Decode raw hex from tx output
		const script = Script.fromHex(hex);
    
		//Pop signature off the end
    const signature = script.chunks.pop().buf.toString();
    
		//Pop address off the end
    const address = script.chunks.pop().buf.toString();
    
    //If unsafe OP_RETURN skip 1 chunk, else skip 2, remove ecdsa chunks and extract buffers
    const chunks = script.chunks.splice(script.chunks[0].opcodenum === 0 ? 2 : 1, script.chunks.length-5).map(c => c.buf);
        
    //Grab string parts and validate
    const parts = sha256(Buffer.from(chunks.map(c => c.toString()).join(' '))).toString('hex');
		let partsValid = bsvMessage.verify(parts, address, signature);
    
    //Grab buffer parts and validate
    const bufferParts = sha256(Buffer.concat(chunks.map(c => Buffer.from(c)))).toString('hex');
		let bufferPartsValid = bsvMessage.verify(bufferParts, address, signature);
    
    let m;
    
    if(partsValid){
			m = bsvMessage(parts).magicHash();    	
    } else if(bufferPartsValid){
    	m = bsvMessage(bufferParts).magicHash()
    } else {
    	throw (new Error("Invalid signature"));
    }
		
    //Try to recover the pubkey
		const sig = bsv.crypto.Signature.fromCompact(bsv.deps.Buffer.from(signature, 'base64'));
    const ecdsa = new bsv.crypto.ECDSA();
    ecdsa.hashbuf = m;
    ecdsa.sig = sig;
    const publicKey = ecdsa.toPublicKey();
    if(Address.fromPublicKey(publicKey).toString() === address){
			return publicKey.toString('hex');    
    } else {
			throw(new Error("Address mismatch. Recovery failed."));
		}
}

const twetchHex =...