Skip to content
This repository was archived by the owner on Feb 24, 2021. It is now read-only.

Commit 7f9d699

Browse files
committed
ooth-twitter
1 parent d19d05a commit 7f9d699

12 files changed

+316
-0
lines changed

packages/ooth-twitter/.prettierignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.json
2+
build/
3+
node_modules/

packages/ooth-twitter/.prettierrc

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"singleQuote": true,
3+
"printWidth": 125,
4+
"trailingComma": "all",
5+
"arrowParens": "always"
6+
}

packages/ooth-twitter/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Ooth Twitter
2+
3+
This is a package of the [ooth project](https://github.com/nmaro/ooth).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es6",
4+
"module": "commonjs",
5+
"moduleResolution": "node",
6+
"removeComments": false,
7+
"outDir": "../lib",
8+
"rootDir": "../src",
9+
"declaration": true,
10+
"sourceMap": false,
11+
"strict": true,
12+
"noUnusedLocals": true,
13+
"noUnusedParameters": true,
14+
"lib": ["es2016"]
15+
},
16+
"include": ["../src/**/*"],
17+
"exclude": []
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "./tsconfig.base.json"
3+
}

packages/ooth-twitter/jest.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"collectCoverage": true,
3+
"transform": {
4+
"^.+\\.tsx?$": "ts-jest"
5+
},
6+
"testMatch": ["**/test/**/*.test.ts"],
7+
"testPathIgnorePatterns": ["/node_modules/"],
8+
"moduleFileExtensions": ["ts", "tsx", "js", "json"]
9+
}

packages/ooth-twitter/package.json

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "ooth-twitter",
3+
"version": "2.6.0",
4+
"description": "",
5+
"main": "lib/index.js",
6+
"scripts": {
7+
"clean": "del-cli ./lib ./coverage",
8+
"build": "npm run clean && tsc -p ./config/tsconfig.build.json",
9+
"lint": "tslint -c ./tslint.json -p ./config/tsconfig.build.json",
10+
"test": "npm run lint && npm run clean && jest -c ./jest.json",
11+
"test:watch": "npm run clean && jest -c ./jest.json --watch"
12+
},
13+
"author": "Nicola Marcacci Rossi <[email protected]> (http://nmr.io)",
14+
"license": "MIT",
15+
"engines": {
16+
"node": ">= 10.9.0"
17+
},
18+
"repository": "nmaro/ooth",
19+
"devDependencies": {
20+
"@smartive/tslint-config": "^4.0.0",
21+
"@types/express": "^4.16.0",
22+
"@types/jest": "^23.3.1",
23+
"@types/mongodb": "^3.1.12",
24+
"@types/passport": "^0.4.6",
25+
"@types/request-promise": "^4.1.42",
26+
"del-cli": "^1.1.0",
27+
"express": "^4.16.2",
28+
"jest": "^23.5.0",
29+
"mongodb": "^2.2.33",
30+
"mongodb-memory-server": "^2.0.1",
31+
"ms": "^2.1.1",
32+
"ooth-mongo": "^2.6.0",
33+
"request-promise": "^4.2.2",
34+
"ts-jest": "^23.1.4",
35+
"tslint": "^5.11.0",
36+
"tslint-config-prettier": "^1.15.0",
37+
"tsutils": "^3.0.0",
38+
"typescript": "^3.0.1"
39+
},
40+
"dependencies": {
41+
"ooth": "^2.6.0",
42+
"passport-custom": "^1.0.5",
43+
"qs": "^6.6.0",
44+
"request": "^2.88.0"
45+
}
46+
}

packages/ooth-twitter/src/index.ts

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { FullRequest, Ooth, StrategyValues } from 'ooth';
2+
3+
const request = require('request');
4+
const qs = require('qs');
5+
6+
const { Strategy } = require('passport-custom');
7+
8+
type Config = {
9+
name?: string;
10+
ooth: Ooth;
11+
clientID: string;
12+
clientSecret: string;
13+
callbackUrl: string;
14+
};
15+
16+
export default function({ name = 'twitter', ooth, clientID, clientSecret, callbackUrl }: Config): void {
17+
ooth.registerUniqueField(name, 'email', 'email');
18+
ooth.registerProfileFields(name, 'email');
19+
ooth.registerStrategyUniqueField(name, 'id');
20+
21+
ooth.registerMethod(
22+
name,
23+
'reverse',
24+
[],
25+
async () =>
26+
new Promise((res, rej) =>
27+
request.post(
28+
{
29+
url: 'https://api.twitter.com/oauth/request_token',
30+
oauth: {
31+
callback: callbackUrl,
32+
consumer_key: clientID,
33+
consumer_secret: clientSecret,
34+
},
35+
headers: {
36+
Accept: 'application/json',
37+
},
38+
},
39+
(err: Error, _: any, body: string) => {
40+
if (err) {
41+
return rej(err);
42+
}
43+
44+
if (body.indexOf('errors') > -1) {
45+
try {
46+
return rej(new Error(JSON.parse(body).errors[0].message));
47+
} catch (e) {
48+
return rej(new Error(`Unexpected error: ${e.message}`));
49+
}
50+
}
51+
52+
res(qs.parse(body));
53+
},
54+
),
55+
),
56+
);
57+
58+
ooth.registerPrimaryConnect(
59+
name,
60+
'login',
61+
[],
62+
new Strategy(async (req: FullRequest, done: (e: Error | null, v: StrategyValues) => void) => {
63+
const { oauth_token, oauth_verifier } = req.body;
64+
request.post(
65+
{
66+
url: 'https://api.twitter.com/oauth/access_token',
67+
oauth: {
68+
consumer_key: clientID,
69+
consumer_secret: clientSecret,
70+
token: oauth_token,
71+
},
72+
form: {
73+
oauth_verifier,
74+
},
75+
},
76+
(err: Error, _: any, body: string) => {
77+
if (err) {
78+
return done(err, {});
79+
}
80+
81+
if (body.indexOf('errors') > -1) {
82+
try {
83+
return done(new Error(JSON.parse(body).errors[0].message), {});
84+
} catch (e) {
85+
return done(new Error(`Unexpected error: ${e.message}`), {});
86+
}
87+
}
88+
89+
const { oauth_token, oauth_token_secret, user_id, screen_name } = qs.parse(body);
90+
91+
request.get(
92+
{
93+
url: 'https://api.twitter.com/1.1/account/verify_credentials.json?include_email=true',
94+
oauth: {
95+
consumer_key: clientID,
96+
consumer_secret: clientSecret,
97+
token: oauth_token,
98+
token_secret: oauth_token_secret,
99+
},
100+
},
101+
(err: Error, _: any, body: string) => {
102+
if (err) {
103+
return done(err, {});
104+
}
105+
106+
const data = JSON.parse(body);
107+
108+
if (data.errors) {
109+
return done(new Error(data.errors[0].message), {});
110+
}
111+
112+
done(null, {
113+
token: oauth_token,
114+
tokenSecret: oauth_token_secret,
115+
id: user_id,
116+
username: screen_name,
117+
email: data.email,
118+
});
119+
},
120+
);
121+
},
122+
);
123+
}),
124+
);
125+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`ooth-twitter fails to log in with valid token 1`] = `
4+
Object {
5+
"message": "Invalid or expired token.",
6+
"status": "error",
7+
}
8+
`;
+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import * as express from 'express';
2+
import { MongoClient, Db } from 'mongodb';
3+
import MongodbMemoryServer from 'mongodb-memory-server';
4+
import { Ooth } from 'ooth';
5+
import { OothMongo } from 'ooth-mongo';
6+
import * as request from 'request-promise';
7+
8+
import oothTwitter from '../src';
9+
import { Server } from 'http';
10+
11+
let mongoServer: MongodbMemoryServer;
12+
let con: MongoClient;
13+
let app: express.Express;
14+
let server: Server;
15+
let ooth: Ooth;
16+
let oothMongo: OothMongo;
17+
let db: Db;
18+
19+
const startServer = () => {
20+
return new Promise((resolve) => {
21+
server = app.listen(8080, resolve);
22+
});
23+
};
24+
25+
describe('ooth-twitter', () => {
26+
beforeAll(async () => {
27+
mongoServer = new MongodbMemoryServer();
28+
const connectionString = await mongoServer.getConnectionString();
29+
const dbName = await mongoServer.getDbName();
30+
con = await MongoClient.connect(connectionString);
31+
db = con.db(dbName);
32+
});
33+
34+
afterAll(async () => {
35+
await con.close();
36+
await mongoServer.stop();
37+
});
38+
39+
beforeEach(async () => {
40+
app = express();
41+
oothMongo = new OothMongo(db);
42+
ooth = new Ooth({
43+
app,
44+
backend: oothMongo,
45+
path: '',
46+
});
47+
oothTwitter({
48+
ooth,
49+
clientID: 'XXX',
50+
clientSecret: 'XXX',
51+
callbackUrl: 'http://localhost:8080/oauth/twitter',
52+
});
53+
await startServer();
54+
});
55+
56+
afterEach(async () => {
57+
if (server) {
58+
await server.close();
59+
}
60+
if (db) {
61+
await db.dropDatabase();
62+
}
63+
});
64+
65+
test('fails to log in with valid token', async () => {
66+
try {
67+
await request({
68+
method: 'POST',
69+
uri: 'http://localhost:8080/twitter/login',
70+
json: true,
71+
body: {
72+
oauth_token: 'XXX',
73+
},
74+
});
75+
} catch (e) {
76+
expect(e.response.statusCode).toBe(400);
77+
expect(e.response.body).toMatchSnapshot();
78+
}
79+
});
80+
});

packages/ooth-twitter/tsconfig.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "./config/tsconfig.base.json",
3+
"compilerOptions": {
4+
"watch": true,
5+
"sourceMap": true
6+
}
7+
}

packages/ooth-twitter/tslint.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": ["@smartive/tslint-config", "tslint-config-prettier"],
3+
"rules": {
4+
"arrow-parens": true,
5+
"ter-arrow-parens": "as-needed",
6+
"ordered-imports": false
7+
}
8+
}

0 commit comments

Comments
 (0)