feat: replace Helia with Pinata (#9)

* wip: testing pinata

* fix: replace helia with pinata.cloud

* chore: update gitignore

* feat: replace ipfs with pinata
This commit is contained in:
tsukino
2024-03-15 03:42:23 -04:00
committed by GitHub
parent 68de583281
commit 45322e33cc
9 changed files with 15717 additions and 1789 deletions

4
.env.sample Normal file
View File

@@ -0,0 +1,4 @@
PINATA_API_SECRET=""
PINATA_API_KEY=""
PINATA_GATEWAY=""
PINATA_GATEWAY_KEY=""

17429
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -27,14 +27,15 @@
"dependencies": {
"@fortawesome/fontawesome-free": "^6.4.2",
"@helia/unixfs": "^3.0.0",
"@pinata/sdk": "^2.1.0",
"@types/node-forge": "^1.3.11",
"buffer": "^6.0.3",
"charwise": "^3.0.1",
"classnames": "^2.3.2",
"dotenv": "^16.4.5",
"express": "^4.18.2",
"express-fileupload": "^1.4.3",
"fast-deep-equal": "^3.1.3",
"helia": "^4.0.1",
"isomorphic-fetch": "^3.0.0",
"multiformats": "^13.1.0",
"node-forge": "^1.3.1",

View File

@@ -2,6 +2,13 @@
TLSN Explorer is server that will handle the social discovery and visualization of proofs generated from the TLS Notary protocol.
## Set up .env
1. `cp .env.sample .env`
2. Create an API key in [Pinata.cloud](https://docs.pinata.cloud/quickstart/node-js#generate-your-api-keys)
3. Create a new Gateway in [Pinata.cloud](https://app.pinata.cloud/gateway)
4. Create a new Gateway access token in [Pinata.cloud](https://app.pinata.cloud/developers/gateway-settings)
5. Update your `.env` file
## Development
```bash
npm i

View File

@@ -1,3 +1,4 @@
import 'dotenv/config';
import express from 'express';
import fileUpload from 'express-fileupload';
import stream from 'stream';
@@ -26,23 +27,22 @@ app.use(fileUpload({
limits: { fileSize: 1024 * 1024 }, // 1mb file limit
}));
app.post('/upload', async (req, res) => {
app.post('/api/upload', async (req, res) => {
for (const file of Object.values(req.files!)) {
// @ts-ignore
const data = file.data;
const cid = await addBytes(data);
res.send(JSON.stringify(cid.toString()));
res.json(cid);
return;
}
res.status(400).send({ error: true, message: 'request is missing file' });
});
app.get('/ipfs/:cid', async (req, res) => {
app.get('/gateway/ipfs/:cid', async (req, res) => {
const cid = req.params.cid;
const file = await getCID(req.params.cid);
console.log(file);
const readStream = new stream.PassThrough();
readStream.end(Buffer.from(file));
res.set('Content-Type', 'application/octet-stream');

View File

@@ -1,27 +1,31 @@
import { createHelia, HeliaLibp2p } from 'helia';
import { unixfs } from '@helia/unixfs';
import { CID } from 'multiformats/cid'
import pinataSDK from '@pinata/sdk';
import { Readable } from 'stream';
const PINATA_API_KEY = process.env.PINATA_API_KEY;
const PINATA_API_SECRET = process.env.PINATA_API_SECRET;
const pinata = new pinataSDK(PINATA_API_KEY, PINATA_API_SECRET);
let node: HeliaLibp2p | null = null;
export async function addBytes(file: Buffer) {
const res = await pinata.pinFileToIPFS(Readable.from(file), {
pinataMetadata: {
name: 'proof.json',
},
pinataOptions: {
cidVersion: 1
}
});
export async function getIPFS() {
if (!node)
node = await createHelia();
return node;
}
export async function addBytes(buf: Buffer) {
const ipfs = await getIPFS();
const fs = unixfs(ipfs);
const cid = await fs.addBytes(buf);
return cid;
if (res.IpfsHash) return res.IpfsHash;
return null;
}
export async function getCID(hash: string) {
const ipfs = await getIPFS();
const cid = CID.parse(hash);
const file = await ipfs.blockstore.get(cid);
return file;
console.log(process.env.PINATA_GATEWAY + '/' + hash);
const res = await fetch(process.env.PINATA_GATEWAY + '/ipfs/' + hash, {
headers: {
'x-pinata-gateway-token': process.env.PINATA_GATEWAY_KEY!,
}
});
return res.text();
}

View File

@@ -60,7 +60,9 @@ const ProofDetails: React.FC<ProofDetailsProps> = ({proof, cid, file}): ReactEle
};
const proofToDisplay = selectedProof?.proof || proof;
const inputValue = process.env.NODE_ENV === "development" ? `http://localhost:3000/${selectedProof?.ipfsCID ? selectedProof?.ipfsCID : cid}` : `www.tlsnexplorer.com/${selectedProof?.ipfsCID ? selectedProof?.ipfsCID : cid}`;
const inputValue = process.env.NODE_ENV === "development"
? `http://localhost:3000/${selectedProof?.ipfsCID ? selectedProof?.ipfsCID : cid}`
: `www.tlsnexplorer.com/${selectedProof?.ipfsCID ? selectedProof?.ipfsCID : cid}`;
// TODO - Format proof details for redacted data

View File

@@ -20,7 +20,7 @@ export default function SharedProof(): ReactElement {
setErrors('No CID provided');
return;
}
const response = await fetch(`/ipfs/${cid}`);
const response = await fetch(`/gateway/ipfs/${cid}`);
if (!response.ok) {
setErrors('Failed to fetch file from IPFS');
throw new Error('Failed to fetch file from IPFS');
@@ -28,6 +28,7 @@ export default function SharedProof(): ReactElement {
const data = await response.json();
try {
const proof = await verify(data, notaryKey);
console.log(data);
setVerifiedProof(proof);
} catch (e) {

View File

@@ -11,7 +11,7 @@ export const uploadFileToIpfs = (file: File) => {
formData.append('file', file);
try {
const response = await fetch('/upload', {
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});