noblox.js-secure 4.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of noblox.js-secure might be problematic. Click here for more details.
- package/.eslintrc.js +21 -0
- package/.github/FUNDING.yml +2 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- package/.github/dependabot.yml +12 -0
- package/.github/workflows/doc-publish.yml +33 -0
- package/.github/workflows/npmpublish.yml +70 -0
- package/.travis.yml +13 -0
- package/CODE_OF_CONDUCT.md +76 -0
- package/LICENSE +21 -0
- package/README.md +168 -0
- package/examples/cleanPlayers.js +130 -0
- package/examples/cleanWall.js +110 -0
- package/examples/revertRanks.js +100 -0
- package/examples/savePlayers.js +119 -0
- package/examples/saveWall.js +96 -0
- package/img/moderatedThumbnails/moderatedThumbnail_100x100.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_110x110.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_140x140.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_150x150.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_150x200.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_180x180.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_250x250.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_30x30.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_352x352.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_420x420.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_48x48.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_50x50.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_60x60.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_720x720.png +0 -0
- package/img/moderatedThumbnails/moderatedThumbnail_75x75.png +0 -0
- package/img/noblox-js-small.png +0 -0
- package/img/noblox-js.png +0 -0
- package/img/thumbnailSizes.png +0 -0
- package/jsDocsConfig.json +55 -0
- package/lib/accountinformation/getUserSocialLinks.js +42 -0
- package/lib/accountsettings/block.js +58 -0
- package/lib/accountsettings/unblock.js +58 -0
- package/lib/asset/deleteFromInventory.js +69 -0
- package/lib/asset/getProductInfo.js +56 -0
- package/lib/asset/uploadAnimation.js +103 -0
- package/lib/asset/uploadItem.js +83 -0
- package/lib/asset/uploadModel.js +90 -0
- package/lib/avatar/avatarRules.js +38 -0
- package/lib/avatar/currentlyWearing.js +32 -0
- package/lib/avatar/getAvatar.js +35 -0
- package/lib/avatar/getCurrentAvatar.js +37 -0
- package/lib/avatar/getRecentItems.js +37 -0
- package/lib/avatar/outfitDetails.js +32 -0
- package/lib/avatar/outfits.js +37 -0
- package/lib/avatar/redrawAvatar.js +48 -0
- package/lib/avatar/removeAssetId.js +55 -0
- package/lib/avatar/setAvatarBodyColors.js +60 -0
- package/lib/avatar/setAvatarScales.js +60 -0
- package/lib/avatar/setPlayerAvatarType.js +50 -0
- package/lib/avatar/setWearingAssets.js +50 -0
- package/lib/avatar/wearAssetId.js +55 -0
- package/lib/badges/getAwardedTimestamps.js +52 -0
- package/lib/badges/getBadgeInfo.js +43 -0
- package/lib/badges/getGameBadges.js +62 -0
- package/lib/badges/getPlayerBadges.js +28 -0
- package/lib/badges/updateBadgeInfo.js +80 -0
- package/lib/cache/add.js +14 -0
- package/lib/cache/addIf.js +26 -0
- package/lib/cache/clear.js +8 -0
- package/lib/cache/get.js +28 -0
- package/lib/cache/index.js +17 -0
- package/lib/cache/new.js +12 -0
- package/lib/cache/wrap.js +25 -0
- package/lib/chat/addUsersToConversation.js +61 -0
- package/lib/chat/chatSettings.js +33 -0
- package/lib/chat/getChatMessages.js +40 -0
- package/lib/chat/getConversations.js +43 -0
- package/lib/chat/getRolloutSettings.js +35 -0
- package/lib/chat/getUnreadConversationCount.js +33 -0
- package/lib/chat/getUnreadMessages.js +38 -0
- package/lib/chat/getUserConversations.js +37 -0
- package/lib/chat/markChatAsRead.js +52 -0
- package/lib/chat/markChatAsSeen.js +50 -0
- package/lib/chat/multiGetLatestMessages.js +37 -0
- package/lib/chat/onNewConversation.js +50 -0
- package/lib/chat/onNewMessage.js +53 -0
- package/lib/chat/onNewMessageBySelf.js +50 -0
- package/lib/chat/onUserOnline.js +50 -0
- package/lib/chat/onUserTyping.js +54 -0
- package/lib/chat/removeFromGroupConversation.js +62 -0
- package/lib/chat/renameGroupConversation.js +57 -0
- package/lib/chat/sendChatMessage.js +57 -0
- package/lib/chat/setChatUserTyping.js +61 -0
- package/lib/chat/start121Conversation.js +50 -0
- package/lib/chat/startCloudEditConversation.js +50 -0
- package/lib/chat/startGroupConversation.js +62 -0
- package/lib/client/onNotification.js +70 -0
- package/lib/client/setAPIKey.js +18 -0
- package/lib/client/setCookie.js +38 -0
- package/lib/datastores/deleteDatastoreEntry.js +66 -0
- package/lib/datastores/getDatastoreEntry.js +98 -0
- package/lib/datastores/getDatastoreEntryVersions.js +83 -0
- package/lib/datastores/getDatastoreKeys.js +73 -0
- package/lib/datastores/getDatastores.js +72 -0
- package/lib/datastores/incrementDatastoreEntry.js +93 -0
- package/lib/datastores/setDatastoreEntry.js +90 -0
- package/lib/develop/canManage.js +44 -0
- package/lib/develop/configureItem.js +142 -0
- package/lib/develop/updateUniverse.js +53 -0
- package/lib/develop/updateUniverseAccess.js +55 -0
- package/lib/economy/buy.js +99 -0
- package/lib/economy/getGroupFunds.js +43 -0
- package/lib/economy/getGroupRevenueSummary.js +48 -0
- package/lib/economy/getGroupTransactions.js +32 -0
- package/lib/economy/getResaleData.js +54 -0
- package/lib/economy/getResellers.js +35 -0
- package/lib/economy/getUserTransactions.js +34 -0
- package/lib/economy/onGroupTransaction.js +74 -0
- package/lib/friends/acceptFriendRequest.js +59 -0
- package/lib/friends/declineAllFriendRequests.js +57 -0
- package/lib/friends/declineFriendRequest.js +59 -0
- package/lib/friends/getFollowers.js +61 -0
- package/lib/friends/getFollowings.js +61 -0
- package/lib/friends/getFriendRequests.js +56 -0
- package/lib/friends/getFriends.js +53 -0
- package/lib/friends/onFriendRequest.js +58 -0
- package/lib/friends/removeFriend.js +58 -0
- package/lib/friends/sendFriendRequest.js +59 -0
- package/lib/friends/unfollow.js +58 -0
- package/lib/games/addDeveloperProduct.js +64 -0
- package/lib/games/checkDeveloperProductName.js +39 -0
- package/lib/games/configureGamePass.js +146 -0
- package/lib/games/getDeveloperProducts.js +51 -0
- package/lib/games/getGameInstances.js +31 -0
- package/lib/games/getGamePasses.js +39 -0
- package/lib/games/getGameSocialLinks.js +45 -0
- package/lib/games/getGroupGames.js +30 -0
- package/lib/games/getUniverseInfo.js +51 -0
- package/lib/games/updateDeveloperProduct.js +69 -0
- package/lib/groups/changeRank.js +59 -0
- package/lib/groups/deleteWallPost.js +64 -0
- package/lib/groups/deleteWallPostsByUser.js +59 -0
- package/lib/groups/demote.js +25 -0
- package/lib/groups/exile.js +59 -0
- package/lib/groups/getAuditLog.js +64 -0
- package/lib/groups/getGroup.js +55 -0
- package/lib/groups/getGroupSocialLinks.js +44 -0
- package/lib/groups/getGroups.js +88 -0
- package/lib/groups/getJoinRequest.js +52 -0
- package/lib/groups/getJoinRequests.js +58 -0
- package/lib/groups/getPlayers.js +108 -0
- package/lib/groups/getRankInGroup.js +52 -0
- package/lib/groups/getRankNameInGroup.js +52 -0
- package/lib/groups/getRole.js +64 -0
- package/lib/groups/getRolePermissions.js +51 -0
- package/lib/groups/getRoles.js +56 -0
- package/lib/groups/getShout.js +49 -0
- package/lib/groups/getWall.js +59 -0
- package/lib/groups/groupPayout.js +103 -0
- package/lib/groups/handleJoinRequest.js +60 -0
- package/lib/groups/leaveGroup.js +60 -0
- package/lib/groups/onAuditLog.js +61 -0
- package/lib/groups/onJoinRequest.js +63 -0
- package/lib/groups/onJoinRequestHandle.js +105 -0
- package/lib/groups/onShout.js +57 -0
- package/lib/groups/onWallPost.js +58 -0
- package/lib/groups/promote.js +25 -0
- package/lib/groups/searchGroups.js +32 -0
- package/lib/groups/setGroupDescription.js +65 -0
- package/lib/groups/setGroupName.js +66 -0
- package/lib/groups/setRank.js +79 -0
- package/lib/groups/shout.js +65 -0
- package/lib/index.js +30 -0
- package/lib/internal/levelOneCopy.js +16 -0
- package/lib/internal/queue.js +61 -0
- package/lib/internal/timeout.js +30 -0
- package/lib/internal/wrap.js +78 -0
- package/lib/inventory/getCollectibles.js +31 -0
- package/lib/inventory/getInventory.js +32 -0
- package/lib/inventory/getInventoryById.js +31 -0
- package/lib/inventory/getOwnership.js +54 -0
- package/lib/inventory/getUAIDs.js +47 -0
- package/lib/itemconfiguration/getGroupAssets.js +32 -0
- package/lib/options.js +26 -0
- package/lib/party/onPartyDeleted.js +53 -0
- package/lib/party/onPartyInvite.js +53 -0
- package/lib/party/onPartyJoinedGame.js +53 -0
- package/lib/party/onPartyLeftGame.js +53 -0
- package/lib/party/onPartySelfJoined.js +53 -0
- package/lib/party/onPartySelfLeft.js +53 -0
- package/lib/party/onPartyUserJoined.js +53 -0
- package/lib/party/onPartyUserLeft.js +53 -0
- package/lib/premiumfeatures/getPremium.js +51 -0
- package/lib/presence/getPresences.js +63 -0
- package/lib/privatemessages/getMessages.js +60 -0
- package/lib/privatemessages/message.js +80 -0
- package/lib/privatemessages/onMessage.js +88 -0
- package/lib/thumbnails/getLogo.js +60 -0
- package/lib/thumbnails/getPlayerThumbnail.js +121 -0
- package/lib/thumbnails/getThumbnails.js +93 -0
- package/lib/trades/acceptTrade.js +58 -0
- package/lib/trades/canTradeWith.js +48 -0
- package/lib/trades/counterTrade.js +84 -0
- package/lib/trades/declineTrade.js +58 -0
- package/lib/trades/getTradeInfo.js +52 -0
- package/lib/trades/getTrades.js +37 -0
- package/lib/trades/sendTrade.js +82 -0
- package/lib/users/getBlurb.js +36 -0
- package/lib/users/getIdFromUsername.js +53 -0
- package/lib/users/getPlayerInfo.js +100 -0
- package/lib/users/getUsernameFromId.js +44 -0
- package/lib/users/onBlurbChange.js +46 -0
- package/lib/util/clearSession.js +32 -0
- package/lib/util/generalRequest.js +61 -0
- package/lib/util/getAction.js +45 -0
- package/lib/util/getCurrentUser.js +44 -0
- package/lib/util/getGeneralToken.js +52 -0
- package/lib/util/getHash.js +29 -0
- package/lib/util/getInputs.js +37 -0
- package/lib/util/getPageResults.js +89 -0
- package/lib/util/getSenderUserId.js +30 -0
- package/lib/util/getSession.js +38 -0
- package/lib/util/getVerification.js +60 -0
- package/lib/util/getVerificationInputs.js +31 -0
- package/lib/util/http.js +110 -0
- package/lib/util/jar.js +24 -0
- package/lib/util/refreshCookie.js +52 -0
- package/lib/util/relog.js +81 -0
- package/lib/util/setOptions.js +54 -0
- package/lib/util/shortPoll.js +102 -0
- package/lib/util/threaded.js +80 -0
- package/package.json +91 -0
- package/postinstall.js +1 -0
- package/settings.json +101 -0
- package/test/accountinformation.test.js +27 -0
- package/test/accountsettings.test.js +27 -0
- package/test/asset.test.js +66 -0
- package/test/assets/Great-White-Shark-Fin.rbxm +0 -0
- package/test/assets/KeyframeSequence.rbxm +0 -0
- package/test/avatar.test.js +164 -0
- package/test/badges.test.js +96 -0
- package/test/chat.test.js +104 -0
- package/test/datastore.test.js +105 -0
- package/test/develop.test.js +53 -0
- package/test/economy.test.js +137 -0
- package/test/friends.test.js +128 -0
- package/test/games.test.js +187 -0
- package/test/groups.test.js +311 -0
- package/test/inventory.test.js +98 -0
- package/test/itemconfiguration.test.js +24 -0
- package/test/premiumfeatures.test.js +17 -0
- package/test/presence.test.js +25 -0
- package/test/privatemessages.test.js +33 -0
- package/test/thumbnails.test.js +53 -0
- package/test/users.test.js +68 -0
- package/tutorials/Authentication.md +75 -0
- package/tutorials/Event Emitters.md +26 -0
- package/tutorials/Promises.md +86 -0
- package/tutorials/VPS Authentication.md +72 -0
- package/typings/index.d.ts +2493 -0
- package/typings/jsDocs.ts +1883 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Includes
|
|
2
|
+
const settings = require('../../settings.json')
|
|
3
|
+
const options = require('../options.js')
|
|
4
|
+
|
|
5
|
+
// Args
|
|
6
|
+
exports.optional = ['jar']
|
|
7
|
+
|
|
8
|
+
// Docs
|
|
9
|
+
/**
|
|
10
|
+
* 🔐 Get the .ROBLOSECURITY cookie from the jar.
|
|
11
|
+
* @category Utility
|
|
12
|
+
* @alias getSession
|
|
13
|
+
* @param {CookieJar=} jar - The cookie jar containing the .ROBLOSECURITY cookie.
|
|
14
|
+
* @returns {string}
|
|
15
|
+
* @example const noblox = require("noblox.js")
|
|
16
|
+
* // Login using your cookie.
|
|
17
|
+
* const cookie = await noblox.getSession()
|
|
18
|
+
**/
|
|
19
|
+
|
|
20
|
+
// Define
|
|
21
|
+
exports.func = function (args) {
|
|
22
|
+
const jar = args.jar || options.jar
|
|
23
|
+
if (settings.session_only) {
|
|
24
|
+
if (typeof jar === 'string') {
|
|
25
|
+
return jar
|
|
26
|
+
}
|
|
27
|
+
return jar.session
|
|
28
|
+
} else {
|
|
29
|
+
const cookies = jar.getCookies('https://roblox.com')
|
|
30
|
+
for (let i = 0; i < cookies.length; i++) {
|
|
31
|
+
const element = cookies[i]
|
|
32
|
+
if (element.key === '.ROBLOSECURITY') {
|
|
33
|
+
return element.value
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return ''
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Includes
|
|
2
|
+
const http = require('./http.js').func
|
|
3
|
+
const getHash = require('./getHash.js').func
|
|
4
|
+
const getVerificationInputs = require('./getVerificationInputs.js').func
|
|
5
|
+
const cache = require('../cache')
|
|
6
|
+
const URL = require('url').URL
|
|
7
|
+
|
|
8
|
+
// Args
|
|
9
|
+
exports.required = ['url']
|
|
10
|
+
exports.optional = ['ignoreCache', 'getBody', 'jar']
|
|
11
|
+
|
|
12
|
+
// Docs
|
|
13
|
+
/**
|
|
14
|
+
* 🔐 Get the RequestVerificationToken from a url.
|
|
15
|
+
* @category Utility
|
|
16
|
+
* @alias getVerification
|
|
17
|
+
* @param {string} url - The url to get the token from.
|
|
18
|
+
* @param {boolean=} [ignoreCache=false] - Determines whether the cache be ignored or not.
|
|
19
|
+
* @param {boolean=} [getBody=false] - If the body and inputs should be returned in an object
|
|
20
|
+
* @param {CookieJar=} jar - The CookieJar containing the .ROBLOSECURITY cookie.
|
|
21
|
+
* @returns {Promise<GetVerificationResponse>}
|
|
22
|
+
* @example const noblox = require("noblox.js")
|
|
23
|
+
* // Login using your cookie.
|
|
24
|
+
* const verificationTokenInfo = await noblox.getVerification()
|
|
25
|
+
**/
|
|
26
|
+
|
|
27
|
+
// Define
|
|
28
|
+
function getVerification (jar, url, getBody) {
|
|
29
|
+
const httpOpt = {
|
|
30
|
+
url: url,
|
|
31
|
+
options: {
|
|
32
|
+
resolveWithFullResponse: true,
|
|
33
|
+
jar: jar
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return http(httpOpt)
|
|
37
|
+
.then(function (res) {
|
|
38
|
+
const inputs = getVerificationInputs({ html: res.body })
|
|
39
|
+
let match
|
|
40
|
+
if (res.headers && res.headers['set-cookie']) {
|
|
41
|
+
match = res.headers['set-cookie'].toString().match(/__RequestVerificationToken=(.*?);/)
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
body: (getBody ? res.body : null),
|
|
45
|
+
inputs: inputs,
|
|
46
|
+
header: match && match[1]
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
exports.func = function (args) {
|
|
52
|
+
const jar = args.jar
|
|
53
|
+
if (args.ignoreCache) {
|
|
54
|
+
return getVerification(jar, args.url, args.getBody)
|
|
55
|
+
} else {
|
|
56
|
+
return cache.wrap('Verify', new URL(args.url).pathname + getHash({ jar: jar }), function () {
|
|
57
|
+
return getVerification(jar, args.url, args.getBody)
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Dependencies
|
|
2
|
+
const parser = require('cheerio')
|
|
3
|
+
|
|
4
|
+
// Args
|
|
5
|
+
exports.required = [['html', 'selector']]
|
|
6
|
+
|
|
7
|
+
// Docs
|
|
8
|
+
/**
|
|
9
|
+
* ✅ Get the verification inputs from the html.
|
|
10
|
+
* @category Utility
|
|
11
|
+
* @alias getVerificationInputs
|
|
12
|
+
* @param {string | function} html | selector - The html to search or the cheerio selector to use.
|
|
13
|
+
* @returns {Inputs}
|
|
14
|
+
* @example const noblox = require("noblox.js")
|
|
15
|
+
* const inputs = noblox.getVerificationInputs("htmlstuff")
|
|
16
|
+
**/
|
|
17
|
+
|
|
18
|
+
// Define
|
|
19
|
+
exports.func = function (args) {
|
|
20
|
+
let $ = args.selector
|
|
21
|
+
if (!$) {
|
|
22
|
+
$ = parser.load(args.html)
|
|
23
|
+
}
|
|
24
|
+
const inputs = {}
|
|
25
|
+
const find = ['__VIEWSTATE', '__VIEWSTATEGENERATOR', '__EVENTVALIDATION', '__RequestVerificationToken']
|
|
26
|
+
for (let i = 0; i < find.length; i++) {
|
|
27
|
+
const get = find[i]
|
|
28
|
+
inputs[get] = $('input[name=' + get + ']').val()
|
|
29
|
+
}
|
|
30
|
+
return inputs
|
|
31
|
+
}
|
package/lib/util/http.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// Dependencies
|
|
2
|
+
let request = require('request-promise')
|
|
3
|
+
|
|
4
|
+
// Includes
|
|
5
|
+
const options = require('../options.js')
|
|
6
|
+
const settings = require('../../settings.json')
|
|
7
|
+
const cache = require('../cache')
|
|
8
|
+
const getHash = require('./getHash.js').func
|
|
9
|
+
|
|
10
|
+
// Args
|
|
11
|
+
exports.required = ['url']
|
|
12
|
+
exports.optional = ['options', 'ignoreLoginError']
|
|
13
|
+
|
|
14
|
+
// Define
|
|
15
|
+
request = request.defaults({
|
|
16
|
+
forever: true,
|
|
17
|
+
agentOptions: {
|
|
18
|
+
maxSockets: Infinity
|
|
19
|
+
},
|
|
20
|
+
simple: false,
|
|
21
|
+
gzip: true,
|
|
22
|
+
timeout: settings.timeout
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
// Docs
|
|
26
|
+
/**
|
|
27
|
+
* ✅ Send an http request to url with options.
|
|
28
|
+
* @category Utility
|
|
29
|
+
* @alias http
|
|
30
|
+
* @param {string} url - The url to request to.
|
|
31
|
+
* @param {object} options - The options to send with the request.
|
|
32
|
+
* @param {boolean} ignoreLoginError - If any login errors should be ignored.
|
|
33
|
+
* @returns {Promise<string>}
|
|
34
|
+
* @example const noblox = require("noblox.js")
|
|
35
|
+
* const body = await noblox.http("https://roblox.com/login", { method: "GET" })
|
|
36
|
+
**/
|
|
37
|
+
|
|
38
|
+
function http (url, opt) {
|
|
39
|
+
if (opt && !opt.jar && Object.keys(opt).indexOf('jar') > -1) {
|
|
40
|
+
opt.jar = options.jar
|
|
41
|
+
}
|
|
42
|
+
if (settings.session_only && opt && opt.jar) {
|
|
43
|
+
if (!opt.headers) {
|
|
44
|
+
opt.headers = {}
|
|
45
|
+
}
|
|
46
|
+
opt.headers.cookie = '.ROBLOSECURITY=' + opt.jar.session + ';'
|
|
47
|
+
opt.headers['x-api-key'] = opt.jar.apiKey
|
|
48
|
+
opt.jar = null
|
|
49
|
+
}
|
|
50
|
+
if (opt && opt.verification) {
|
|
51
|
+
if (!opt.headers) {
|
|
52
|
+
opt.headers = {}
|
|
53
|
+
}
|
|
54
|
+
const verify = '__RequestVerificationToken=' + opt.verification + ';'
|
|
55
|
+
if (opt.headers.cookie) {
|
|
56
|
+
opt.headers.cookie += verify
|
|
57
|
+
} else {
|
|
58
|
+
opt.headers.cookie = verify
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (url.indexOf('http') !== 0) {
|
|
62
|
+
url = 'https:' + url
|
|
63
|
+
}
|
|
64
|
+
return request(url, opt)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
exports.func = function (args) {
|
|
68
|
+
const opt = args.options || {}
|
|
69
|
+
if (typeof opt.jar === 'string') {
|
|
70
|
+
opt.jar = { session: opt.jar }
|
|
71
|
+
}
|
|
72
|
+
const jar = opt.jar
|
|
73
|
+
let depth = args.depth || 0
|
|
74
|
+
const full = opt.resolveWithFullResponse || false
|
|
75
|
+
opt.resolveWithFullResponse = true
|
|
76
|
+
const follow = opt.followRedirect === undefined || opt.followRedirect
|
|
77
|
+
opt.followRedirect = function (res) {
|
|
78
|
+
if (!args.ignoreLoginError && res.headers.location && (res.headers.location.startsWith('https://www.roblox.com/newlogin') || res.headers.location.startsWith('/Login/Default.aspx'))) {
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
return follow
|
|
82
|
+
}
|
|
83
|
+
return http(args.url, opt).then(function (res) {
|
|
84
|
+
if (opt && opt.headers && opt.headers['X-CSRF-TOKEN']) {
|
|
85
|
+
if (res.statusCode === 403 && (res.statusMessage === 'XSRF Token Validation Failed' || res.statusMessage === 'Token Validation Failed')) {
|
|
86
|
+
depth++
|
|
87
|
+
if (depth >= 3) {
|
|
88
|
+
throw new Error('Tried ' + depth + ' times and could not refresh XCSRF token successfully')
|
|
89
|
+
}
|
|
90
|
+
const token = res.headers['x-csrf-token']
|
|
91
|
+
if (token) {
|
|
92
|
+
opt.headers['X-CSRF-TOKEN'] = token
|
|
93
|
+
opt.jar = jar
|
|
94
|
+
args.depth = depth + 1
|
|
95
|
+
return exports.func(args)
|
|
96
|
+
} else {
|
|
97
|
+
throw new Error('Could not refresh X-CSRF-TOKEN')
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
if (depth > 0) {
|
|
101
|
+
cache.add(options.cache, 'XCSRF', getHash({ jar: jar }), opt.headers['X-CSRF-TOKEN'])
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (res.statusCode === 302 && !args.ignoreLoginError && res.headers.location && (res.headers.location.startsWith('https://www.roblox.com/newlogin') || res.headers.location.startsWith('/Login/Default.aspx'))) {
|
|
106
|
+
throw new Error('You are not logged in')
|
|
107
|
+
}
|
|
108
|
+
return full ? res : res.body
|
|
109
|
+
})
|
|
110
|
+
}
|
package/lib/util/jar.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Dependencies
|
|
2
|
+
const request = require('request-promise')
|
|
3
|
+
|
|
4
|
+
// Includes
|
|
5
|
+
const settings = require('../../settings.json')
|
|
6
|
+
|
|
7
|
+
// Docs
|
|
8
|
+
/**
|
|
9
|
+
* ✅ Create a jar file based on sessionOnly.
|
|
10
|
+
* @category Utility
|
|
11
|
+
* @alias jar
|
|
12
|
+
* @param {boolean=} sessionOnly - The session to use to create the jar file.
|
|
13
|
+
* @returns {CookieJar}
|
|
14
|
+
* @example const noblox = require("noblox.js")
|
|
15
|
+
* const jar = noblox.jar()
|
|
16
|
+
**/
|
|
17
|
+
|
|
18
|
+
// Define
|
|
19
|
+
exports.func = function (sessionOnly) {
|
|
20
|
+
if (!sessionOnly) {
|
|
21
|
+
sessionOnly = settings.session_only
|
|
22
|
+
}
|
|
23
|
+
return (sessionOnly ? { session: '' } : request.jar())
|
|
24
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Includes
|
|
2
|
+
const options = require('../options.js')
|
|
3
|
+
const getGeneralToken = require('./getGeneralToken.js').func
|
|
4
|
+
const http = require('./http.js').func
|
|
5
|
+
// Args
|
|
6
|
+
exports.required = []
|
|
7
|
+
exports.optional = ['cookie']
|
|
8
|
+
|
|
9
|
+
// Docs
|
|
10
|
+
/**
|
|
11
|
+
* 🔐 Refreshes the stored cookie, stores it, and returns it.
|
|
12
|
+
* @category Utility
|
|
13
|
+
* @deprecated [Retrieving your .ROBLOSECURITY cookie in incognito mode should make a cookie that does not expire.]{@link https://noblox.js.org/tutorial-Authentication.html}
|
|
14
|
+
* @alias refreshCookie
|
|
15
|
+
* @param {string=} cookie - The cookie to refresh.
|
|
16
|
+
* @returns {Promise<string>}
|
|
17
|
+
* @example const noblox = require("noblox.js")
|
|
18
|
+
* const newCookie = await noblox.refreshCookie("COOKIEHERE")
|
|
19
|
+
**/
|
|
20
|
+
|
|
21
|
+
// Refreshes the internally stored cookie, or the cookie provided
|
|
22
|
+
// Stores the new cookie & returns it
|
|
23
|
+
function refreshCookie (cookie) {
|
|
24
|
+
if (cookie) {
|
|
25
|
+
options.jar.session = cookie
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return getGeneralToken({}).then((token) => {
|
|
29
|
+
return http({
|
|
30
|
+
url: 'https://www.roblox.com/authentication/signoutfromallsessionsandreauthenticate',
|
|
31
|
+
options: {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
resolveWithFullResponse: true,
|
|
34
|
+
jar: null,
|
|
35
|
+
headers: {
|
|
36
|
+
'X-CSRF-TOKEN': token
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}).then((res) => {
|
|
40
|
+
const cookies = res.headers['set-cookie']
|
|
41
|
+
if (cookies) {
|
|
42
|
+
const cookie = cookies.toString().match(/\.ROBLOSECURITY=(.*?);/)[1]
|
|
43
|
+
options.jar.session = cookie
|
|
44
|
+
return cookie
|
|
45
|
+
} else {
|
|
46
|
+
throw new Error('Failed to refresh cookie: None returned.')
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = refreshCookie
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Includes
|
|
2
|
+
const options = require('../options.js')
|
|
3
|
+
const getGeneralToken = require('./getGeneralToken.js').func
|
|
4
|
+
const getVerification = require('./getVerification.js').func
|
|
5
|
+
const getCurrentUser = require('./getCurrentUser.js').func
|
|
6
|
+
const http = require('./http.js').func
|
|
7
|
+
const cookieFile = './cookie'
|
|
8
|
+
const fs = require('fs')
|
|
9
|
+
// Args
|
|
10
|
+
exports.required = ['cookie']
|
|
11
|
+
exports.optional = []
|
|
12
|
+
|
|
13
|
+
const day = 86400000
|
|
14
|
+
|
|
15
|
+
// Define
|
|
16
|
+
const relog = (cookie) => {
|
|
17
|
+
if (!cookie) throw new Error('no cookie supplied?')
|
|
18
|
+
options.jar.session = cookie
|
|
19
|
+
return getVerification({ url: 'https://www.roblox.com/my/account#!/security' })
|
|
20
|
+
.then((ver) => {
|
|
21
|
+
if (!ver.header) console.log('Bad cookie.')
|
|
22
|
+
return getGeneralToken({}).then((token) => {
|
|
23
|
+
return http({
|
|
24
|
+
url: 'https://www.roblox.com/authentication/signoutfromallsessionsandreauthenticate',
|
|
25
|
+
options: {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
resolveWithFullResponse: true,
|
|
28
|
+
verification: ver.header,
|
|
29
|
+
jar: null,
|
|
30
|
+
headers: {
|
|
31
|
+
'X-CSRF-TOKEN': token
|
|
32
|
+
},
|
|
33
|
+
form: {
|
|
34
|
+
__RequestVerificationToken: ver.inputs.__RequestVerificationToken
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}).then((res) => {
|
|
38
|
+
const cookies = res.headers['set-cookie']
|
|
39
|
+
if (cookies) {
|
|
40
|
+
options.jar.session = cookies.toString().match(/\.ROBLOSECURITY=(.*?);/)[1]
|
|
41
|
+
|
|
42
|
+
fs.writeFile(cookieFile, JSON.stringify({ cookie: options.jar.session, time: Date.now() }), (err) => {
|
|
43
|
+
if (err) {
|
|
44
|
+
console.error('Failed to write cookie')
|
|
45
|
+
}
|
|
46
|
+
return true
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
module.exports = c
|
|
54
|
+
|
|
55
|
+
async function c (cookie) {
|
|
56
|
+
// Check for file
|
|
57
|
+
if (fs.existsSync(cookieFile)) {
|
|
58
|
+
const json = JSON.parse(fs.readFileSync(cookieFile))
|
|
59
|
+
|
|
60
|
+
// Check its new enough
|
|
61
|
+
if (json.time + day > Date.now()) {
|
|
62
|
+
// Its recent enough. Try it.
|
|
63
|
+
try {
|
|
64
|
+
await relog(json.cookie)
|
|
65
|
+
return getCurrentUser({})
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.log('Stored relog failed. Trying with given.')
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (cookie) {
|
|
72
|
+
// Try the user's cookie
|
|
73
|
+
try {
|
|
74
|
+
await relog(cookie)
|
|
75
|
+
return getCurrentUser({})
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.error(e)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
throw new Error('No cookie supplied and no cookie file available.')
|
|
81
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const settings = require('../../settings.json')
|
|
2
|
+
|
|
3
|
+
// Docs
|
|
4
|
+
/**
|
|
5
|
+
* ✅ Updates library options. This allows you to modify settings such as time-out, or number of event retries without
|
|
6
|
+
* altering the settings.json file. Objects passed to this function should match the format of the settings.json file.
|
|
7
|
+
* Unknown keys, or malformed options will be rejected with an error.
|
|
8
|
+
* @category Utility
|
|
9
|
+
* @param {NobloxOptions} newOptions - The new options to set, structured as per [settings.json](https://github.com/noblox/noblox.js/blob/master/settings.json)
|
|
10
|
+
* @returns void
|
|
11
|
+
* @see [settings.json](https://github.com/noblox/noblox.js/blob/master/settings.json) - default package settings
|
|
12
|
+
* @example const noblox = require("noblox.js")
|
|
13
|
+
* // This example overrides getPlayerThumbnail()'s response URL when a thumbnail is moderated.
|
|
14
|
+
* // You usually want to run this before logging in with your cookie.
|
|
15
|
+
* noblox.setOptions({
|
|
16
|
+
* thumbnail: {
|
|
17
|
+
* failedUrl: {
|
|
18
|
+
* blocked: "https://raw.githubusercontent.com/noblox/noblox.js/master/img/noblox-js.png"
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* })
|
|
22
|
+
*/
|
|
23
|
+
function setOptions (newOptions) {
|
|
24
|
+
return setOptionsLevel(settings, newOptions)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// This function allows key validation to be performed at different "levels" of nesting.
|
|
28
|
+
// Ensures the provided keys already exist, and discards invalid keys.
|
|
29
|
+
function setOptionsLevel (settingsLevel, inputObj) {
|
|
30
|
+
const keys = Object.keys(inputObj)
|
|
31
|
+
|
|
32
|
+
for (const key of keys) {
|
|
33
|
+
const newValue = inputObj[key]
|
|
34
|
+
const currentValue = settingsLevel[key]
|
|
35
|
+
|
|
36
|
+
if (currentValue !== undefined) {
|
|
37
|
+
if (typeof currentValue === 'object') {
|
|
38
|
+
if (typeof inputObj[key] !== 'object') {
|
|
39
|
+
throw new Error(`Tried to set options key ${key}, an object, to a non-object value: ${newValue}`)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setOptionsLevel(currentValue, newValue)
|
|
43
|
+
} else {
|
|
44
|
+
// it's not undefined, and it's not a nested object - set the value.
|
|
45
|
+
settingsLevel[key] = newValue
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
// The key doesn't exist
|
|
49
|
+
throw new Error(`Tried to set option "${key}". This option does not exist, or has been nested incorrectly.`)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
exports.func = setOptions
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Dependencies
|
|
2
|
+
const events = require('events')
|
|
3
|
+
|
|
4
|
+
// Includes
|
|
5
|
+
const settings = require('../../settings.json')
|
|
6
|
+
const promiseTimeout = require('../internal/timeout')
|
|
7
|
+
|
|
8
|
+
// Args
|
|
9
|
+
exports.required = ['getLatest', 'delay']
|
|
10
|
+
exports.optional = ['timeout']
|
|
11
|
+
|
|
12
|
+
// Docs
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {function} getLatest
|
|
15
|
+
* @param {number} latest - A value representing the latest version.
|
|
16
|
+
* @param {EventEmitter} event - The event emitter to emit to.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* ✅ This is the base for events that do not rely on true streams. The `getLatest` function receives some value that represents the latest version of something (eg. a date or unique ID) and determines if there is new information, every time it is fired it waits `delay` ms before being fired again. Every time it must return an object with the field `latest`, representing the latest value (which will not change if new information was not received), and an array `data` which has the new values (if there are multiple they each have their own index, if there is only one then it is by itself in the array). If `latest` is equal to -2, the returned data will be processed even if it is the initial run (which usually only establishes the latest value). If the return object has a true `repeat` value, the function latest will be run again immediately after. If `delay` is a string it will take the number from that string key in the `event` object of the settings.json file.
|
|
21
|
+
* When the function is first called it will initialize `getLatest` with the value -1 and then emit the `connect` event. Whenever data is received, it will emit the `data` event for each value. If the `close` event is emitted the function will no longer run. If an error occurs the `error` event will be emitted, the function will log a retry and after the number of max retries as specified by settings, it will emit the `close` event.
|
|
22
|
+
* The `getLatest` function will be marked as failed if it does not resolve within `timeout` ms (which can be disabled if timeout is negative). If getLatest fails for any reason (including timeout) it will be retried `maxRetries` times before stopping.
|
|
23
|
+
* @category Utility
|
|
24
|
+
* @alias shortPoll
|
|
25
|
+
* @param {function} getLatest - The function to use to get the latest. Should return an object with key 'data' - an array containing output data,
|
|
26
|
+
* and the new 'latest' value.
|
|
27
|
+
* @returns {Promise<GetLatestResponse>}
|
|
28
|
+
**/
|
|
29
|
+
|
|
30
|
+
// Define
|
|
31
|
+
exports.func = function (args) {
|
|
32
|
+
const latest = args.getLatest
|
|
33
|
+
let delay = args.delay
|
|
34
|
+
delay = (typeof delay === 'string' || delay instanceof String ? settings.event[delay] : delay) || settings.event.defaultDelay
|
|
35
|
+
let retries = 0
|
|
36
|
+
const max = settings.event.maxRetries
|
|
37
|
+
const timeout = args.timeout || settings.event.timeout
|
|
38
|
+
let stop = false
|
|
39
|
+
let current
|
|
40
|
+
const evt = new events.EventEmitter()
|
|
41
|
+
const run = function (value) {
|
|
42
|
+
if (stop) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
let promise = latest(value, evt)
|
|
46
|
+
if (timeout > 0) {
|
|
47
|
+
promise = promiseTimeout(promise, timeout)
|
|
48
|
+
}
|
|
49
|
+
return promise.then(function (response) {
|
|
50
|
+
if (stop) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
if (value === -1) {
|
|
54
|
+
current = response.latest
|
|
55
|
+
}
|
|
56
|
+
retries = 0
|
|
57
|
+
const data = response.data
|
|
58
|
+
if (data.length > 0 && (value !== -1 || current === -2)) {
|
|
59
|
+
current = response.latest
|
|
60
|
+
for (let i = 0; i < data.length; i++) {
|
|
61
|
+
evt.emit('data', data[i])
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (response.repeat) {
|
|
65
|
+
run(current)
|
|
66
|
+
} else {
|
|
67
|
+
setTimeout(run, delay, current)
|
|
68
|
+
}
|
|
69
|
+
return response
|
|
70
|
+
})
|
|
71
|
+
.catch(function (err) {
|
|
72
|
+
if (stop) {
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
evt.emit('error', err)
|
|
76
|
+
retries++
|
|
77
|
+
if (retries > max) {
|
|
78
|
+
evt.emit('close', new Error('Max retries reached'))
|
|
79
|
+
} else {
|
|
80
|
+
setTimeout(run, delay, current)
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
run(-1)
|
|
86
|
+
.then(function (response) {
|
|
87
|
+
if (stop) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
evt.emit('connect', response.latest)
|
|
91
|
+
})
|
|
92
|
+
.catch(function (err) {
|
|
93
|
+
evt.emit('close', new Error('Initialization failed: ' + err.message))
|
|
94
|
+
})
|
|
95
|
+
evt.on('close', function (err) {
|
|
96
|
+
stop = true
|
|
97
|
+
if (err) {
|
|
98
|
+
evt.emit('error', err)
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
return evt
|
|
102
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Includes
|
|
2
|
+
const settings = require('../../settings.json')
|
|
3
|
+
|
|
4
|
+
// Args
|
|
5
|
+
exports.required = ['getPage', 'start', 'end']
|
|
6
|
+
|
|
7
|
+
// Define
|
|
8
|
+
exports.func = function (args) {
|
|
9
|
+
const getPage = args.getPage
|
|
10
|
+
const start = args.start
|
|
11
|
+
const end = args.end
|
|
12
|
+
let completed = 0
|
|
13
|
+
let expected = end - start
|
|
14
|
+
let rslv
|
|
15
|
+
function next (i, ivl, tries) {
|
|
16
|
+
if (i >= end) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
if (i < start) {
|
|
20
|
+
next(i + ivl, ivl, 0)
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
if (tries > 2) {
|
|
24
|
+
expected--
|
|
25
|
+
console.error('Ran out of tries for ' + i)
|
|
26
|
+
if (completed >= expected) {
|
|
27
|
+
rslv()
|
|
28
|
+
} else {
|
|
29
|
+
next(i + ivl, ivl, 0)
|
|
30
|
+
}
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
const res = getPage(i)
|
|
34
|
+
if (res && res.then) {
|
|
35
|
+
res.then(function () {
|
|
36
|
+
completed++
|
|
37
|
+
if (completed >= expected) {
|
|
38
|
+
rslv()
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
next(i + ivl, ivl, 0)
|
|
42
|
+
})
|
|
43
|
+
.catch(function (err) {
|
|
44
|
+
if (!err.stack.includes('ESOCKETTIMEDOUT')) { // Silence common socket timeout errors
|
|
45
|
+
console.error('Thread error: ' + err.stack)
|
|
46
|
+
}
|
|
47
|
+
setTimeout(next, 5000, i, ivl, tries + 1)
|
|
48
|
+
})
|
|
49
|
+
} else {
|
|
50
|
+
expected--
|
|
51
|
+
if (completed >= expected) {
|
|
52
|
+
rslv()
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
next(i + ivl, ivl, 0)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const promise = new Promise(function (resolve) {
|
|
60
|
+
rslv = resolve
|
|
61
|
+
if (expected <= 0) {
|
|
62
|
+
resolve()
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
const ivl = Math.min(settings.maxThreads, expected)
|
|
66
|
+
for (let i = 0; i < ivl; i++) {
|
|
67
|
+
next(i, ivl, 0)
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
promise.getStatus = function () {
|
|
71
|
+
return Math.round((completed / expected) * 10000) / 100 || 0
|
|
72
|
+
}
|
|
73
|
+
promise.getCompleted = function () {
|
|
74
|
+
return completed
|
|
75
|
+
}
|
|
76
|
+
promise.getExpected = function () {
|
|
77
|
+
return expected
|
|
78
|
+
}
|
|
79
|
+
return promise
|
|
80
|
+
}
|