Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
@team11ingsw/twitter-lite
Advanced tools
Tiny, full-featured client/server REST/stream library for the Twitter API
A tiny, full-featured, modern client / server library for the Twitter API.
We have built this library because existing ones have not been recently maintained, or depend on outdated libraries.
yarn add twitter-lite
npm install twitter-lite
Then you can include the following at the top of your code:
import Twitter from 'twitter-lite';
const client = new Twitter({
...
})
client.get(...)
client.post(...)
Twitter has two different authentication options:
User authentication requires:
consumer_key
consumer_secret
access_token_key
access_token_secret
App authentication requires:
bearer_token
App authentication is a simple header behind the scenes:
headers: {
Authorization: `Bearer ${bearer_token}`;
}
You can get the bearer token by calling .getBearerToken()
.
const client = new Twitter({
subdomain: "api", // "api" is the default (change for other subdomains)
version: "1.1", // version "1.1" is the default (change for other subdomains)
consumer_key: "abc", // from Twitter.
consumer_secret: "def", // from Twitter.
access_token_key: "uvw", // from your User (oauth_token)
access_token_secret: "xyz" // from your User (oauth_token_secret)
});
client
.get("account/verify_credentials")
.then(results => {
console.log("results", results);
})
.catch(console.error);
const user = new Twitter({
consumer_key: "abc",
consumer_secret: "def"
});
const response = await user.getBearerToken();
const app = new Twitter({
bearer_token: response.access_token
});
According to the docs this helps you get access token from your users.
const client = new Twitter({
consumer_key: "xyz",
consumer_secret: "xyz"
});
client
.getRequestToken("http://callbackurl.com")
.then(res =>
console.log({
reqTkn: res.oauth_token,
reqTknSecret: res.oauth_token_secret
})
)
.catch(console.error);
Then you redirect your user to https://api.twitter.com/oauth/authenticate?oauth_token=xyz123abc
, and once you get the verifier and the token, you pass them on to the next stage of the authentication.
const client = new Twitter({
consumer_key: "xyz",
consumer_secret: "xyz"
});
client
.getAccessToken({
oauth_verifier: oauthVerifier,
oauth_token: oauthToken
})
.then(res =>
console.log({
accTkn: res.oauth_token,
accTknSecret: res.oauth_token_secret,
userId: res.user_id,
screenName: res.screen_name
})
)
.catch(console.error);
And this will return you your access_token
and access_token_secret
.
const client = new Twitter({
consumer_key: "xyz",
consumer_secret: "xyz",
access_token_key: "xyz",
access_token_secret: "xyz"
});
async function tweetThread(thread) {
let lastTweetID = "";
for (const status of thread) {
const tweet = await client.post("statuses/update", {
status: status,
in_reply_to_status_id: lastTweetID,
auto_populate_reply_metadata: true
});
lastTweetID = tweet.id_str;
}
}
const thread = ["First tweet", "Second tweet", "Third tweet"];
tweetThread(thread).catch(console.error);
To learn more about the streaming API visit the Twitter Docs. The streaming API works only in Node.
const client = new Twitter({
consumer_key: "xyz" // from Twitter.
consumer_secret: "xyz" // from Twitter.
access_token_key: "abc" // from your User (oauth_token)
access_token_secret: "abc" // from your User (oauth_token_secret)
});
const parameters = {
track: "#bitcoin,#litecoin,#monero",
follow: "422297024,873788249839370240", // @OrchardAI, @tylerbuchea
locations: "-122.75,36.8,-121.75,37.8", // Bounding box - San Francisco
};
const stream = client.stream("statuses/filter", parameters)
.on("start", response => console.log("start"))
.on("data", tweet => console.log("data", tweet.text))
.on("ping", () => console.log("ping"))
.on("error", error => console.log("error", error))
.on("end", response => console.log("end"));
// To stop the stream:
process.nextTick(() => stream.destroy()); // emits "end" and "error" events
To stop a stream, call stream.destroy()
. That might take a while though, if the stream receives a lot of traffic. Also, if you attempt to destroy a stream from an on
handler, you may get an error about writing to a destroyed stream.
In that case, try to defer the destroy()
call:
process.nextTick(() => stream.destroy());
After calling stream.destroy()
, you can recreate the stream, if you wait long enough - see the "should reuse stream N times" test. Note that Twitter may return a "420 Enhance your calm" error if you switch streams too fast. There are no response headers specifying how long to wait, and the error, as well as streaming limits in general, are poorly documented. Trial and error has shown that for tracked keywords, waiting 20 to 30 seconds between re-creating streams was enough. Remember to also set up the .on()
handlers again for the new stream.
The new Twitter API v2 no longer requires the .json
extension on its endpoints. In order to use v2
, set version: '2'
and extension: false
.
const client = new Twitter({
version: "2", // version "1.1" is the default (change for v2)
extension: false, // true is the default (this must be set to false for v2 endpoints)
consumer_key: "abc", // from Twitter.
consumer_secret: "def", // from Twitter.
access_token_key: "uvw", // from your User (oauth_token)
access_token_secret: "xyz" // from your User (oauth_token_secret)
});
Returns a Promise resolving to the API response object, or rejecting on error. The response and error objects also contain the HTTP response code and headers, under the _headers
key. These are useful to check for rate limit information.
const client = new Twitter({
consumer_key: "xyz",
consumer_secret: "xyz",
access_token_key: "abc",
access_token_secret: "abc"
});
const rateLimits = await client.get("statuses/show", {
id: "1016078154497048576"
});
Same return as .get()
.
Use the .post
method for actions that change state, or when the total size of the parameters might be too long for a GET request. For example, to follow a user:
const client = new Twitter({
consumer_key: "xyz",
consumer_secret: "xyz",
access_token_key: "abc",
access_token_secret: "abc"
});
await client.post("friendships/create", {
screen_name: "dandv"
});
The second use case for POST is when you need to pass more parameters than suitable for the length of a URL, such as when looking up a larger number of user ids or screen names:
const users = await client.post("users/lookup", {
screen_name: "longScreenName1,longerScreeName2,...,veryLongScreenName100"
});
Same return as .get()
and .post()
.
Use the .put
method for actions that update state. For example, to update a welcome message.
const client = new Twitter({
consumer_key: "xyz",
consumer_secret: "xyz",
access_token_key: "abc",
access_token_secret: "abc"
});
const welcomeMessageID = "abc";
await client.put(
"direct_messages/welcome_messages/update",
{
id: welcomeMessageID
},
{
message_data: {
text: "Welcome!!!"
}
}
);
See the app authentication example.
See the OAuth example.
See the OAuth example.
You can find many more examples for various resources/endpoints in the tests.
const tweets = await client.get("statuses/home_timeline");
console.log(`Rate: ${tweets._headers.get('x-rate-limit-remaining')} / ${tweets._headers.get('x-rate-limit-limit')}`);
const delta = (tweets._headers.get('x-rate-limit-reset') * 1000) - Date.now()
console.log(`Reset: ${Math.ceil(delta / 1000 / 60)} minutes`);
.get
and .post
reject on error, so you can use try/catch to handle errors. The error object contains an errors
property with the error code
and message
, and a _headers
property with the the HTTP response code and Headers object returned by the Twitter API.
try {
const response = await client.get("some/endpoint");
// ... use response here ...
} catch (e) {
if ('errors' in e) {
// Twitter API error
if (e.errors[0].code === 88)
// rate limit exceeded
console.log("Rate limit will reset on", new Date(e._headers.get("x-rate-limit-reset") * 1000));
else
// some other kind of error, e.g. read-only API trying to POST
} else {
// non-API error, e.g. network problem or invalid JSON in response
}
}
A particular case of errors is exceeding the rate limits. See the example immediately above for detecting rate limit errors, and read Twitter's documentation on rate limiting.
Twitter uses numeric IDs that in practice can be up to 18 characters long. Due to rounding errors, it's unsafe to use numeric IDs in JavaScript. Always set stringify_ids: true
when possible, so that Twitter will return strings instead of numbers, and rely on the id_str
field, rather than on the id
field.
With the library nearing v1.0, contributions are welcome! Areas especially in need of help involve multimedia (see #33 for example), and adding tests (see these for reference).
yarn/npm install
TWITTER_CONSUMER_KEY=...
TWITTER_CONSUMER_SECRET=...
ACCESS_TOKEN=...
ACCESS_TOKEN_SECRET=...
yarn/npm test
and make sure all tests passit()
call to it.skip()
, but remember to revert that change before committing. This will prevent your account from being flagged as abusing the API to send too many DMs.git push
and submit your PR!Authors:
Over the years, thanks to:
FAQs
Tiny, full-featured client/server REST/stream library for the Twitter API
We found that @team11ingsw/twitter-lite demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.