React, Express, Twitter oauth1.0a is sending 215 error - reactjs

Currently I'm using Twitter's OAuth 1.0a.
Since Twitter doesn't allow CORS by itself, I'm trying to send request from Express server.
Since I'm using OAuth 1.0a I'm following https://developer.twitter.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens
To make a request, it says that I need to pass below information as authorization value inside header.
oath_consumer_key
oath_nonce
oauth_signature_method
oauth_timestamp
oauth_version
oauth_token
oath_signature
then I got 215 error.
I tried to regenerate my API keys, tokens but still it throws 215 error.
Below is my code in Express:
const verifyTwitter = async(req,res) => {
const API_BASE_URL = process.env.TWITTER_BASE_URL; // https://api.twitter.com/oauth
const oauth_consumer_key = process.env.TWITTER_CONSUMER_KEY;
const oauth_consumer_key_secret = process.env.TWITTER_CONSUMER_KEY;
const oauth_token = process.env.TWITTER_ACCESS_TOKEN;
const oauth_token_secret = process.env.TWITTER_ACCESS_TOKEN_SECRET;
const ACTION = '/request_token';
let nonceLen = 32;
const oauth_nonce = crypto.randomBytes(Math.ceil(nonceLen * 3 / 4))
.toString('base64')
.slice(0, nonceLen)
.replace(/\+/g, '0')
.replace(/\//g, '0');
const method = 'POST';
const oauth_timestamp = date.toUTCString();
const oauth_signature_method = 'HMAC-SHA1'
const oauth_version = '1.0'
const param_config = `oauth_consumer_key=${oauth_consumer_key}&oauth_nonce=${oauth_nonce}&oauth_signature_method=${oauth_signature_method}&oauth_timestamp=${oauth_timestamp}&oauth_token=${oauth_token}&oauth_version=${oauth_version}`
const oauth_collection_data = `${method}&${API_BASE_URL}&${param_config}`;
const sign_key = `${oauth_consumer_key_secret}&${oauth_token_secret}`;
const oauth_signature = crypto.createHmac('sha1' , sign_key).update(oauth_collection_data).digest('base64')
// const oauth_signature = hmac(sign_key,oauth_collection_data);
const oAuthToken = await needle('post',API_BASE_URL + ACTION + `?oauth_consumer_key=${oauth_consumer_key}`,{},{
headers : {
authorization: `OAuth oauth_consumer_key=${oauth_consumer_key}, oauth_nonce=${oauth_nonce}, oauth_signature_method=${oauth_signature_method}, oauth_timestamp=${oauth_timestamp}, oauth_version=${oauth_version}, oauth_token=${oauth_token} , oauth_signature=${oauth_signature}`
}
}).then(res => {console.dir(res.body); console.log(res.headers)})
return res.status(200)
}

Related

How to upload multiple audio file in react but sending only 3 POST request

I want to select 100 audio file at a time but want to hit only 3 api call at a time. Once these 3 files uploaded (pass or fail) then only other 3 api request will be sent.
Basically I am providing a input field of file type:
<input type="file" multiple name="file" className="myform"
onChange={handleFileChange}
accept="audio/wav"
/>
and I am storing it as array into a state.
Below this I am providing an UPLOAD button.
When user hit on upload, I want to send 3 POST request using axios. once all 3 done either fail or pass then only next 3 should go.
You can do this by iterating the FileList collection in groups of 3 and sending the requests in parallel using Promise.allSettled().
Simply because I cannot recommend Axios, here's a version using the Fetch API
const BATCH_SIZE = 3;
const [fileList, setFileList] = useState([]);
const [uploading, setUploading] = useState(false);
const handleFileChange = (e) => {
setFileList(Array.from(e.target.files)); // just a guess
};
const handleUploadClick = async (e) => {
e.preventDefault();
setUploading(true);
const files = [...fileList]; // avoid mutation during long uploading process
for (let i = 0; i < files.length; i += BATCH_SIZE) {
const result = await Promise.allSettled(
files.slice(i, i + BATCH_SIZE).map(async (file) => {
const body = new FormData();
body.append("file", file);
const res = await fetch(UPLOAD_URL, { method: "POST", body });
return res.ok ? res : Promise.reject(res);
})
);
const passed = result.filter(({ status }) => status === "fulfilled");
console.log(
`Batch ${i + 1}: ${
passed.length
} of ${BATCH_SIZE} requests uploaded successfully`
);
}
setUploading(false);
};
Promise.allSettled() will let you continue after each set of 3 are uploaded, whether they pass or fail.
This method makes 3 separate requests with 1 file each.
With Axios, it would look like this (just replacing the for loop)
for (let i = 0; i < files.length; i += BATCH_SIZE) {
const result = await Promise.allSettled(
files
.slice(i, i + BATCH_SIZE)
.map((file) => axios.postForm(UPLOAD_URL, { file }))
);
const passed = result.filter(({ status }) => status === "fulfilled");
console.log(
`Batch ${i + 1}: ${
passed.length
} of ${BATCH_SIZE} requests uploaded successfully`
);
}
Axios' postForm() method is available from v1.0.0. See https://github.com/axios/axios#files-posting
If you want to send 3 files in a single request, it would look like this for Fetch
for (let i = 0; i < files.length; i += BATCH_SIZE) {
const body = new FormData();
files.slice(i, i + BATCH_SIZE).forEach((file) => {
body.append("file", file); // use "file[]" for the first arg if required
});
try {
const res = await fetch(UPLOAD_URL, { method: "POST", body });
if (!res.ok) {
throw new Error(`${res.status} ${res.statusText}`);
}
console.log(`Batch ${i + 1} passed`);
} catch (err) {
console.warn(`Batch ${i + 1} failed`, err);
}
}
and this for Axios
for (let i = 0; i < files.length; i += BATCH_SIZE) {
try {
await axios.postForm(
{
file: files.slice(i, i + BATCH_SIZE),
},
{
formSerializer: {
indexes: null, // set to false if you need "[]" added
},
}
);
console.log(`Batch ${i + 1} passed`);
} catch (err) {
console.warn(`Batch ${i + 1} failed`, err.response?.data);
}
}
You can use a combination of JavaScript's for loop and Promise.all functions to achieve this. First, you will need to divide your files array into chunks of 3. You can do this using a for loop and the slice method. Next, you can use Promise.all to send all the requests in parallel, and only move on to the next set of requests once all the promises in the current set have been resolved. Here's some sample code that demonstrates this approach:
const chunkSize = 3;
for (let i = 0; i < files.length; i += chunkSize) {
const fileChunk = files.slice(i, i + chunkSize);
const promises = fileChunk.map(file => {
return axios.post('/api/upload', { file });
});
await Promise.all(promises);
}
This will send 3 post request at a time and will wait until all the request are completed before sending another 3 api request.
You can also use useState hook with useEffect to set the state of files that are uploaded and use a variable to keep track of number of files uploaded.
const [uploadedFiles, setUploadedFiles] = useState([]);
const [uploadCount, setUploadCount] = useState(0);
useEffect(() => {
if (uploadCount === files.length) {
// all files have been uploaded
return;
}
const chunkSize = 3;
const fileChunk = files.slice(uploadCount, uploadCount + chunkSize);
const promises = fileChunk.map(file => {
return axios.post('/api/upload', { file });
});
Promise.all(promises).then(responses => {
setUploadedFiles([...uploadedFiles, ...responses]);
setUploadCount(uploadCount + chunkSize);
});
}, [uploadCount]);
This code will work for you.

SSE: Receive JSON from a Flask server through EventSource API

I have a Flask application which responds to a ReactJS application primarily with json. This is important because the Flask app is sending objects from our postgres database.
Recently I started building a "feed" for our website. How I imagine it working: React client issues a GET request to the Flask server for the "items" which will populate the feed. I want to use the EventSource API, using a SSE/stream . This should yield much more fluid page rendering from the user's perspective and allow for much more data to be sent to the client with noticeable loading time (right?).
The problem: EventSource API seems to require a content_type = 'text/event-stream'... which is not ideal for sending objects which much more naturally send as JSON. When I try to send JSON and change the content_type to 'application/json', the browser complains that EventSource was expecting 'text/event-stream'.
My question: is there anything inherent to EventSource which restricts it to 'text/event-stream' responses?
Also! CORS is involved in this process. But I don't think its in the way, because it works for the rest of my app. so this is communication between an app hosted at localhost:5000 and localhost:3000.
Some code:
Flask Server
item_feed.py
#bp.get('/items/stream')
def item_stream():
count = request.args.get("count", None)
def stream_messages_to_client(count):
i = 0
while i < int(count):
data = { "message": "This is a test object."}
# message = "data: This is a test streamable message.\n\n" # This will be received.
message = json.dumps(data) # This will not be received--and this is what I want.
i += 1
yield message
# content_type = 'text/event-stream' # This will be received.
content_type = 'application/json' # This will not be received.
response = Response(stream_with_context(
stream_messages_to_client(count)
), content_type=content_type)
return response
React JS Client
ItemFeed.js
export const ItemFeed = () => {
let [searchParams, setSearchParams] = useSearchParams();
const defaultMessages = [];
const [messages, setMessages] = useState(defaultMessages);
const [isConnectionOpen, setIsConnectionOpen] = useState(false);
const paramsString = searchParams.toString();
const url = process.env.REACT_APP_SERVER + `/items/stream?${paramsString}`;
const eventSource = new EventSource(url, { withCredentials: true })
const handleConnectionOpen = () => {
setIsConnectionOpen(true);
}
const handleStreamedData = (e) => {
// const { message } = JSON.parse(e.data); // This will not parse
const message = e.data; // This will parse, assuming 'data: {{ message }}\n\n'
(messages.length < 10)
? setMessages([...messages, message])
: eventSource.close();
}
const handleConnectionClose = () => {
setIsConnectionOpen(false);
}
eventSource.onopen = handleConnectionOpen;
eventSource.onmessage = handleStreamedData;
eventSource.onclose = handleConnectionClose;
useEffect(() => {
// do something
}, [messages]);
return (
<div className="row">
<p>this is a test</p>
{messages.map((message, index) => (
<div className="col-12" key={message}>{ message }</div>
))}
</div>
);
}

Difficulty in displaying image after passing over blob or datauri to image tag

I'm trying to get an image (served to the client from an express server) to display. I've received the data from the server and have parsed this from binary, to blob, to datauri. I, however, am still getting a broken image on my page.
Below is my code:
const [imageUrl, setImageUrl] = useState('');
const [profilePic, setProfilePic] = useState('');
const [errors, setErrors] = useState('');
const binaryToBase64 = () => {
contentType = contentType || '';
var sliceSize = 1024;
var byteCharacters = base64Data.toString("base64");
var bytesLength = byteCharacters.length;
var slicesCount = Math.ceil(bytesLength / sliceSize);
var byteArrays = new Array(slicesCount);
for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
var begin = sliceIndex * sliceSize;
var end = Math.min(begin + sliceSize, bytesLength);
var bytes = new Array(end - begin);
for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0);
}
byteArrays[sliceIndex] = new Uint8Array(bytes);
}
return new Blob(byteArrays, { type: contentType });
}
useEffect(() => {
// Get all customer media
let tempPhoto = '';
await actions.getMediaReference(customerId)
.then(resp => {
// Set profile pic via reference from DB
tempPhoto = resp.data.find(({ isprofile }) => isprofile);
})
.catch(err => errors.push(err));
await actions.getMediaSource(tempPhoto.key)
.then(resp => {
// console.log("specific data: ", typeof resp.data); // Not sure of the format: ����
const blob = binaryToBase64(resp.request.response, "image/jpg"); // convert to base 64 - I assume I'm getting binary code
const url = URL.createObjectURL(blob);
console.log('blob: ', blob); // prints this which also isn't accepted: blob:http://localhost:3000/1231233234
console.log('url: ', url);
// setImageUrl(url)
// My thinking is that it needed to be further processed (got this from another stackoverflow page)
fileToDataUri(blob)
.then(dataUri => {
setImageUrl(dataUri)
})
setProfilePic({ ...profilePic, image : resp.data });
})
.catch(err => errors.push(err));
}
return(
<>
<img src={imageUrl} />
</>
)
Trying this api out via Postman works - I get the image after a very tiny delay. I can't say that I see the error here but I've tried a few things. After running the base64 code in a converter I can see that something isn't translating correctly. I feel like this shouldn't be that complicated and that I've over-complicated the solution so any help/advice would be much appreciated!
Thanks

TypeError [CLIENT_MISSING_INTENTS]

Today I tried to start my bot but I got this error :
TypeError [CLIENT_MISSING_INTENTS]: Valid intents must be provided for the Client.
[Symbol(code)]: 'CLIENT_MISSING_INTENTS'
And this is my code:
const Discord = require('discord.js'),
client = new Discord.Client(),
nodeHtmlToImage = require('node-html-to-image'),
config = require('./config.json'),
puppeteer = require('puppeteer'),
express = require('express'),
app = express()
var mime = require('mime'),
fs = require('fs'),
path = require('path')
const port = 3e3
async function nitrogenerator(e, t) {
let a = formatAMPM(new Date())
let n = formatAMPM(new Date(Date.now() - 6e4)),
o = await fs.readFileSync(`${__dirname}/testingboost.html`, 'utf8')
;(datatosend = o),
(datatosend = datatosend.replace(
'FIRSTAUTHORURL',
e.author.displayAvatarURL()
)),
(datatosend = datatosend.replace('THEFIRSTAUTHOR', e.author.username)),
(datatosend = datatosend.replace(
'SECONDAUTHORURL',
client.users.cache.random().displayAvatarURL()
)),
(datatosend = datatosend.replace('THESECONDAUTHOR', t.shift())),
(datatosend = datatosend.replace('RESPONSETONITRO', t.join(' '))),
(datatosend = datatosend.replace('FIRSTAUTHORDATE', 'Today at ' + n)),
(datatosend = datatosend.replace('SECONDAUTHORDATE', 'Today at ' + a)),
app.get('/font', function (e, t) {
const a = `${__dirname}/Whitneyfont.woff`
t.sendFile(a)
}),
app.get('/', function (e, t) {
t.send(datatosend)
})
let r = app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
const s = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
}),
i = await s.newPage()
await i.goto(`http://localhost:${port}`),
await i.waitForSelector('.scrollerInner-2YIMLh')
const d = await i.$('.scrollerInner-2YIMLh')
let c = await d.screenshot({ type: 'png' })
await s.close()
const l = new Discord.MessageAttachment(c, 'NitroProof.png')
e.channel.send(`${e.author}`, l), r.close()
}
function formatAMPM(e) {
var t = e.getHours(),
a = e.getMinutes(),
n = t >= 12 ? 'PM' : 'AM'
return (t = (t %= 12) || 12) + ':' + (a = a < 10 ? '0' + a : a) + ' ' + n
}
client.on('ready', () => {
function randomStatus() {
let status = ['ShadowWLX#0001', 'Hehe Boy'] // You can change it whatever you want.
let rstatus = Math.floor(Math.random() * status.length)
// client.user.setActivity(status[rstatus], {type: "WATCHING"});
// You can change the "WATCHING" into STREAMING, LISTENING, and PLAYING.
// Example: streaming
client.user.setActivity(status[rstatus], {
type: 'LISTENING',
url: 'https://discord.gg/MZUHeefXqx',
})
}
setInterval(randomStatus, 5000) // Time in ms. 30000ms = 30 seconds. Min: 20 seconds, to avoid ratelimit.
console.log('Online.')
})
client.on('message', async (e) => {
if ('dm' === e.channel.type) return
if (e.author.bot) return
if (0 !== e.content.indexOf(config.prefix)) return
const t = e.content.slice(config.prefix.length).trim().split(/ +/g)
'boost' === t.shift().toLowerCase() && (await nitrogenerator(e, t))
}),
client.login(config.token)
I know I need to add intents but I don't know how and what intents to add. I think I need to add the GUILD_PRESENCE intent but I don't know how to add it.
You can add intents to the Client like this-
const client = new Discord.Client({
intents: ["GUILD"] //If you want to add all intents just type 32767 instead of array
})
You must add intents in main.js, where you initialize bot.
const myIntents = new Intents();
myIntents.add(Intents.FLAGS.GUILD_PRESENCES, Intents.FLAGS.GUILD_MEMBERS);
const client = new Client({ intents: myIntents });
List of all intents
GUILDS
GUILD_MEMBERS
GUILD_BANS
GUILD_EMOJIS_AND_STICKERS
GUILD_INTEGRATIONS
GUILD_WEBHOOKS
GUILD_INVITES
GUILD_VOICE_STATES
GUILD_PRESENCES
GUILD_MESSAGES
GUILD_MESSAGE_REACTIONS
GUILD_MESSAGE_TYPING
DIRECT_MESSAGES
DIRECT_MESSAGE_REACTIONS
DIRECT_MESSAGE_TYPING
GUILD_SCHEDULED_EVENTS

Want a code that detects custom status and gives the person a role on discord

I am trying to make a code that searches a custom status for the phrase ".gg/RoundTable" and will then give the person a certain role I have in my server.
Here is my code so far , the code runs with no errors but it will not assign the role.
const Discord = require("discord.js")
const client = new Discord.Client()
const mySecret = process.env['TOKEN']
client.login(mySecret)
const roleID = 865801753462702090
client.on('presenceUpdate', async (oldPresence, newPresence) => {
const role = newPresence.guild.roles.cache.find(role => role.name === 'Pic Perms (.gg/RoundTable)');
const status = ".gg/RoundTable"
const member = newPresence.member
console.log(member.user.presence.activities[0].state)
if(member.presence.activities[0].state.includes(status)){
return newPresence.member.roles.add(roleID)
} else {
if(member.roles.cache.has(roleID)) {
newPresence.member.roles.remove(roleID)
}
}
})
Try this:
const Discord = require("discord.js");
const client = new Discord.Client();
const roleID = "851563088314105867";
client.on("presenceUpdate", async (_, newPresence) => {
const role = newPresence.guild.roles.cache.get(roleID);
const status = ".gg/RoundTable";
const member = newPresence.member;
if (member.presence.activities[0].state?.includes(status)) {
return newPresence.member.roles.add(role);
} else {
if (member.roles.cache.has(role)) {
newPresence.member.roles.remove(role);
}
}
});
client.login("your-token");
I'd recommend finding your role in the RoleManager.cache using get() as you already have the roleID and then actually assign that role instead of the roleID. Note I added an optional chaining operator since if a user does not have a custom status .state will be null.

Resources