-
-
Notifications
You must be signed in to change notification settings - Fork 296
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
70fa186
commit d1a1cfd
Showing
6 changed files
with
278 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
const { PinePermManager } = require('../main'); | ||
|
||
/* | ||
This example creates a pine | ||
permission manager and tests | ||
all the available functions | ||
*/ | ||
|
||
const sessionid = process.argv[2]; | ||
const pineid = process.argv[3]; | ||
|
||
const manager = new PinePermManager(sessionid, pineid); | ||
|
||
(async () => { | ||
console.log('Users:', await manager.getUsers()); | ||
|
||
console.log('Adding user \'TradingView\'...'); | ||
|
||
switch (await manager.addUser('TradingView')) { | ||
case 'ok': | ||
console.log('Done !'); | ||
break; | ||
case 'exists': | ||
console.log('This user is already authorized'); | ||
break; | ||
default: | ||
console.error('Unknown error...'); | ||
break; | ||
} | ||
|
||
console.log('Users:', await manager.getUsers()); | ||
|
||
console.log('Modifying expiration date...'); | ||
|
||
const newDate = new Date(Date.now() + 24 * 3600000); // Add one day | ||
if (await manager.modifyExpiration('TradingView', newDate) === 'ok') { | ||
console.log('Done !'); | ||
} else console.error('Unknown error...'); | ||
|
||
console.log('Users:', await manager.getUsers()); | ||
|
||
console.log('Removing expiration date...'); | ||
|
||
if (await manager.modifyExpiration('TradingView') === 'ok') { | ||
console.log('Done !'); | ||
} else console.error('Unknown error...'); | ||
|
||
console.log('Users:', await manager.getUsers()); | ||
|
||
console.log('Removing user \'TradingView\'...'); | ||
|
||
if (await manager.removeUser('TradingView') === 'ok') { | ||
console.log('Done !'); | ||
} else console.error('Unknown error...'); | ||
|
||
console.log('Users:', await manager.getUsers()); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
class FormData { | ||
#string = ''; | ||
|
||
#boundary = ''; | ||
|
||
get boundary() { | ||
return this.#boundary; | ||
} | ||
|
||
constructor() { | ||
const random = (Math.random() * 10 ** 20).toString(36); | ||
this.#boundary = `${random}`; | ||
this.#string = `--${this.boundary}`; | ||
} | ||
|
||
/** | ||
* Adds a property to the FormData object | ||
* @param {string} key Property key | ||
* @param {string} value Property value | ||
*/ | ||
append(key, value) { | ||
this.#string += `\r\nContent-Disposition: form-data; name="${key}"`; | ||
this.#string += `\r\n\r\n${value}`; | ||
this.#string += `\r\n--${this.boundary}`; | ||
} | ||
|
||
/** | ||
* @returns {string} | ||
*/ | ||
toString() { | ||
return `${this.#string}--`; | ||
} | ||
} | ||
|
||
module.exports = FormData; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
const request = require('../request'); | ||
const FormData = require('../FormData'); | ||
|
||
/** | ||
* @typedef {Object} AuthorizationUser | ||
* @prop {id} id User id | ||
* @prop {string} username User's username | ||
* @prop {string} userpic User's profile picture URL | ||
* @prop {string} expiration Authorization expiration date | ||
* @prop {string} created Authorization creation date | ||
*/ | ||
|
||
class PinePermManager { | ||
sessionId; | ||
|
||
pineId; | ||
|
||
/** | ||
* Creates a PinePermManager instance | ||
* @param {string} sessionId Token from sessionid cookie | ||
* @param {string} pineId Indicator ID (Like: PUB;XXXXXXXXXXXXXXXXXXXXX) | ||
*/ | ||
constructor(sessionId, pineId) { | ||
if (!sessionId) throw new Error('Please provide a SessionID'); | ||
if (!pineId) throw new Error('Please provide a PineID'); | ||
this.pineId = pineId; | ||
this.sessionId = sessionId; | ||
} | ||
|
||
/** | ||
* Get list of authorized users | ||
* @param {number} limit Fetching limit | ||
* @param {'user__username' | ||
* | '-user__username' | ||
* | 'created' | 'created' | ||
* | 'expiration,user__username' | ||
* | '-expiration,user__username' | ||
* } order Fetching order | ||
* @returns {AuthorizationUser[]} | ||
*/ | ||
async getUsers(limit = 10, order = '-created') { | ||
const data = await request({ | ||
method: 'POST', | ||
host: 'www.tradingview.com', | ||
path: `/pine_perm/list_users/?limit=${limit}&order_by=${order}`, | ||
headers: { | ||
origin: 'https://www.tradingview.com', | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
cookie: `sessionid=${this.sessionId}`, | ||
}, | ||
}, false, `pine_id=${this.pineId.replace(/;/g, '%3B')}`); | ||
|
||
if (!data.results) throw new Error('Wrong sessionId or pineId'); | ||
|
||
return data.results; | ||
} | ||
|
||
/** | ||
* Adds an user to the authorized list | ||
* @param {string} username User's username | ||
* @param {Date} [expiration] Expiration date | ||
* @returns {'ok' | 'exists' | null} | ||
*/ | ||
async addUser(username, expiration = null) { | ||
const formData = new FormData(); | ||
formData.append('pine_id', this.pineId); | ||
formData.append('username_recip', username); | ||
if (expiration && expiration instanceof Date) { | ||
formData.append('expiration', expiration.toString()); | ||
} | ||
|
||
const data = await request({ | ||
method: 'POST', | ||
host: 'www.tradingview.com', | ||
path: '/pine_perm/add/', | ||
headers: { | ||
origin: 'https://www.tradingview.com', | ||
'Content-Type': `multipart/form-data; boundary=${formData.boundary}`, | ||
cookie: `sessionid=${this.sessionId}`, | ||
}, | ||
}, false, formData.toString()); | ||
|
||
if (!data.status) throw new Error('Wrong sessionId or pineId'); | ||
return data.status; | ||
} | ||
|
||
/** | ||
* Modify an authorization expiration date | ||
* @param {string} username User's username | ||
* @param {Date} [expiration] New expiration date | ||
* @returns {'ok' | null} | ||
*/ | ||
async modifyExpiration(username, expiration = null) { | ||
const formData = new FormData(); | ||
formData.append('pine_id', this.pineId); | ||
formData.append('username_recip', username); | ||
if (expiration && expiration instanceof Date) { | ||
formData.append('expiration', expiration.toISOString()); | ||
} | ||
|
||
const data = await request({ | ||
method: 'POST', | ||
host: 'www.tradingview.com', | ||
path: '/pine_perm/modify_user_expiration/', | ||
headers: { | ||
origin: 'https://www.tradingview.com', | ||
'Content-Type': `multipart/form-data; boundary=${formData.boundary}`, | ||
cookie: `sessionid=${this.sessionId}`, | ||
}, | ||
}, false, formData.toString()); | ||
|
||
if (!data.status) throw new Error('Wrong sessionId or pineId'); | ||
return data.status; | ||
} | ||
|
||
/** | ||
* Removes an user to the authorized list | ||
* @param {string} username User's username | ||
* @returns {'ok' | null} | ||
*/ | ||
async removeUser(username) { | ||
const formData = new FormData(); | ||
formData.append('pine_id', this.pineId); | ||
formData.append('username_recip', username); | ||
|
||
const data = await request({ | ||
method: 'POST', | ||
host: 'www.tradingview.com', | ||
path: '/pine_perm/remove/', | ||
headers: { | ||
origin: 'https://www.tradingview.com', | ||
'Content-Type': `multipart/form-data; boundary=${formData.boundary}`, | ||
cookie: `sessionid=${this.sessionId}`, | ||
}, | ||
}, false, formData.toString()); | ||
|
||
if (!data.status) throw new Error('Wrong sessionId or pineId'); | ||
return data.status; | ||
} | ||
} | ||
|
||
module.exports = PinePermManager; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
const https = require('https'); | ||
|
||
/** | ||
* @param {https.RequestOptions} options HTTPS Request options | ||
* @param {boolean} [raw] Get raw or JSON data | ||
* @param {string} [content] Request body content | ||
* @returns {Promise<string | object | array>} Result | ||
*/ | ||
function request(options = {}, raw = false, content = '') { | ||
return new Promise((cb, err) => { | ||
const req = https.request(options, (res) => { | ||
let data = ''; | ||
res.on('data', (c) => { data += c; }); | ||
res.on('end', () => { | ||
if (raw) { | ||
cb(data); | ||
return; | ||
} | ||
|
||
try { | ||
data = JSON.parse(data); | ||
} catch (error) { | ||
console.log(data); | ||
err(new Error('Can\'t parse server response')); | ||
return; | ||
} | ||
|
||
cb(data); | ||
}); | ||
}); | ||
|
||
req.on('error', err); | ||
req.end(content); | ||
}); | ||
} | ||
|
||
module.exports = request; |