noblox.ts 4.10.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of noblox.ts might be problematic. Click here for more details.
- package/.eslintrc.js +21 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +22 -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/getGamePassProductInfo.js +51 -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 +65 -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/getGameRevenue.js +49 -0
- package/lib/games/getGameSocialLinks.js +45 -0
- package/lib/games/getGroupGames.js +30 -0
- package/lib/games/getPlaceInfo.js +48 -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 +67 -0
- package/lib/groups/getGroup.js +57 -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 +62 -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 +94 -0
- package/postinstall.js +1 -0
- package/settings.json +107 -0
- package/test/accountinformation.test.js +27 -0
- package/test/accountsettings.test.js +27 -0
- package/test/asset.test.js +81 -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 +212 -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 +2525 -0
- package/typings/jsDocs.ts +1927 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
// Includes
|
2
|
+
const http = require('./http.js').func
|
3
|
+
|
4
|
+
// Args
|
5
|
+
exports.required = ['url', 'query', 'limit']
|
6
|
+
exports.optional = ['jar', 'sortOrder']
|
7
|
+
|
8
|
+
// Docs
|
9
|
+
/**
|
10
|
+
* ✅ Handle pagination returned by Roblox.
|
11
|
+
* @category Utility
|
12
|
+
* @alias getPageResults
|
13
|
+
* @param {string} url - The url to retrieve the page results from.
|
14
|
+
* @param {string} query - Any query parameters to add to the url.
|
15
|
+
* @param {SortOrder=} sortOrder - The order to sort the results by.
|
16
|
+
* @param {Limit=} limit - The maximum number of results to return. Following 'pages' of results will be requested until
|
17
|
+
* this limit of results is reached.
|
18
|
+
* @param {string=} pageCursor - Current page index
|
19
|
+
* @returns {Promise<Array>}
|
20
|
+
* @example const noblox = require("noblox.js")
|
21
|
+
* const inventory = await noblox.getPageResults("//inventory.roblox.com/v2/users/1/inventory", "Shirt", "Asc", 100)
|
22
|
+
**/
|
23
|
+
|
24
|
+
// Define
|
25
|
+
function getPageResults (jar, url, query, sortOrder, limit, pageCursor, results) {
|
26
|
+
return new Promise((resolve, reject) => {
|
27
|
+
const allowedLimits = [10, 25, 50, 100]
|
28
|
+
|
29
|
+
const httpOpt = {
|
30
|
+
url: url,
|
31
|
+
options: {
|
32
|
+
qs: {
|
33
|
+
limit: limit <= 100 ? allowedLimits.reduce((prev, curr) => Math.abs(curr - limit) < Math.abs(prev - limit) ? curr : prev) : 100, // Get the most fit page limit within the boundries.
|
34
|
+
cursor: pageCursor || '', // Add page cursor.
|
35
|
+
...query // Add asset types.
|
36
|
+
},
|
37
|
+
method: 'GET',
|
38
|
+
resolveWithFullResponse: true,
|
39
|
+
jar: jar,
|
40
|
+
json: true
|
41
|
+
}
|
42
|
+
}
|
43
|
+
return http(httpOpt).then((res) => {
|
44
|
+
let body = res.body
|
45
|
+
if (typeof (body) === 'string') body = JSON.parse(body.trim())
|
46
|
+
|
47
|
+
const data = body.data
|
48
|
+
|
49
|
+
if (body.errors && body.errors.length > 0) {
|
50
|
+
const errors = body.errors.map((e) => {
|
51
|
+
return e.message
|
52
|
+
})
|
53
|
+
|
54
|
+
return reject(new Error(`${res.statusCode} ${errors.join(', ')}`))
|
55
|
+
}
|
56
|
+
|
57
|
+
results = results ? results.concat(data) : data
|
58
|
+
|
59
|
+
if (results.length > limit) {
|
60
|
+
results = results.slice(0, limit)
|
61
|
+
}
|
62
|
+
|
63
|
+
if (results.length >= limit || data.length === 0 || !body.nextPageCursor) {
|
64
|
+
return resolve(results)
|
65
|
+
}
|
66
|
+
|
67
|
+
resolve(getPageResults(jar, url, query, sortOrder, limit, body.nextPageCursor, results))
|
68
|
+
})
|
69
|
+
.catch(error => reject(error))
|
70
|
+
})
|
71
|
+
}
|
72
|
+
|
73
|
+
function parseDates (results) {
|
74
|
+
return new Promise((resolve, reject) => {
|
75
|
+
if (!results) return resolve([])
|
76
|
+
|
77
|
+
resolve(results.map(result => {
|
78
|
+
if (result.created) result.created = new Date(result.created)
|
79
|
+
if (result.updated) result.updated = new Date(result.updated)
|
80
|
+
return result
|
81
|
+
}))
|
82
|
+
})
|
83
|
+
}
|
84
|
+
|
85
|
+
exports.func = function (args) {
|
86
|
+
return getPageResults(args.jar, args.url, args.query, args.sortOrder, args.limit).then(results => {
|
87
|
+
return parseDates(results)
|
88
|
+
})
|
89
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
// Includes
|
2
|
+
const getCurrentUser = require('./getCurrentUser.js').func
|
3
|
+
const getHash = require('./getHash.js').func
|
4
|
+
const cache = require('../cache')
|
5
|
+
|
6
|
+
// Args
|
7
|
+
exports.optional = ['jar']
|
8
|
+
|
9
|
+
// Docs
|
10
|
+
/**
|
11
|
+
* 🔐 Get the userId of the current user and cache it.
|
12
|
+
* @category Utility
|
13
|
+
* @alias getSenderUserId
|
14
|
+
* @param {CookieJar=} jar - The CookieJar containing the .ROBLOSECURITY cookie.
|
15
|
+
* @returns {Promise<number>}
|
16
|
+
* @example const noblox = require("noblox.js")
|
17
|
+
* // Login using your cookie.
|
18
|
+
* const userId = await noblox.getSenderUserId()
|
19
|
+
**/
|
20
|
+
|
21
|
+
// Define
|
22
|
+
exports.func = function (args) {
|
23
|
+
const jar = args.jar
|
24
|
+
return cache.wrap('SenderID', getHash({ jar: jar }), function () {
|
25
|
+
return getCurrentUser({ jar: jar })
|
26
|
+
.then(function (info) {
|
27
|
+
return info.UserID
|
28
|
+
})
|
29
|
+
})
|
30
|
+
}
|
@@ -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
|
+
}
|