@@ -14,18 +14,23 @@ const path = require('path');
14
14
const fs = require ( 'fs' ) ;
15
15
const { URLSearchParams, URL } = require ( 'url' ) ;
16
16
const multer = require ( 'multer' ) ;
17
+ const { DateTime } = require ( 'luxon' ) ;
17
18
18
19
const app = express ( ) ;
19
20
const upload = multer ( ) ;
20
21
21
22
const DEFAULT_THREADS_QUERY_LIMIT = 10 ;
22
23
23
24
const FIELD__ALT_TEXT = 'alt_text' ;
25
+ const FIELD__APPLICATION = 'application' ;
26
+ const FIELD__APP_SCOPED_USER_ID = 'user_id' ;
24
27
const FIELD__CLICKS = 'clicks' ;
25
28
const FIELD__ERROR_MESSAGE = 'error_message' ;
29
+ const FIELD__EXPIRES_AT = 'expires_at' ;
26
30
const FIELD__FOLLOWERS_COUNT = 'followers_count' ;
27
31
const FIELD__HIDE_STATUS = 'hide_status' ;
28
32
const FIELD__ID = 'id' ;
33
+ const FIELD__ISSUED_AT = 'issued_at' ;
29
34
const FIELD__IS_REPLY = 'is_reply' ;
30
35
const FIELD__IS_VERIFIED = 'is_verified' ;
31
36
const FIELD__LIKES = 'likes' ;
@@ -40,6 +45,7 @@ const FIELD__REPLIES = 'replies';
40
45
const FIELD__REPOSTS = 'reposts' ;
41
46
const FIELD__QUOTES = 'quotes' ;
42
47
const FIELD__REPLY_AUDIENCE = 'reply_audience' ;
48
+ const FIELD__SCOPES = 'scopes' ;
43
49
const FIELD__SHARES = 'shares' ;
44
50
const FIELD__STATUS = 'status' ;
45
51
const FIELD__TEXT = 'text' ;
@@ -63,6 +69,7 @@ const PARAMS__DELETE_CONFIG = 'delete_config';
63
69
const PARAMS__DELETE_QUOTA_USAGE = 'delete_quota_usage' ;
64
70
const PARAMS__FIELDS = 'fields' ;
65
71
const PARAMS__HIDE = 'hide' ;
72
+ const PARAMS__INPUT_TOKEN = 'input_token' ;
66
73
const PARAMS__LINK_ATTACHMENT = 'link_attachment' ;
67
74
const PARAMS__LOCATION_SEARCH_CONFIG = 'location_search_config' ;
68
75
const PARAMS__LOCATION_SEARCH_QUOTA_USAGE = 'location_search_quota_usage' ;
@@ -805,6 +812,37 @@ app.get('/mentions', loggedInUserChecker, async (req, res) => {
805
812
} ) ;
806
813
} ) ;
807
814
815
+ app . get ( '/debug' , loggedInUserChecker , async ( req , res ) => {
816
+ const params = {
817
+ [ PARAMS__INPUT_TOKEN ] : req . session . access_token ,
818
+ } ;
819
+
820
+ const debugAccessTokenUrl = buildGraphAPIURL ( `debug_token` , params , req . session . access_token ) ;
821
+
822
+ let data = { } ;
823
+ try {
824
+ const response = await axios . get ( debugAccessTokenUrl , { httpsAgent : agent } ) ;
825
+ data = response . data . data ;
826
+ } catch ( e ) {
827
+ console . error ( e ?. response ?. data ?. error ?. message ?? e . message ) ;
828
+ }
829
+
830
+ const applicationName = data [ FIELD__APPLICATION ] ;
831
+ const expiresAt = formatTimestamp ( data [ FIELD__EXPIRES_AT ] ) ;
832
+ const issuedAt = formatTimestamp ( data [ FIELD__ISSUED_AT ] ) ;
833
+ const scopes = data [ FIELD__SCOPES ] . join ( ', ' ) ;
834
+ const appScopedUserId = data [ FIELD__APP_SCOPED_USER_ID ] ;
835
+
836
+ return res . render ( 'debug' , {
837
+ title : 'Inspect Access Token' ,
838
+ applicationName,
839
+ expiresAt,
840
+ issuedAt,
841
+ scopes,
842
+ appScopedUserId,
843
+ } ) ;
844
+ } ) ;
845
+
808
846
app . get ( '/keywordSearch' , loggedInUserChecker , async ( req , res ) => {
809
847
const { keyword, searchType } = req . query ;
810
848
@@ -1083,6 +1121,15 @@ function addAttachmentFields(target, attachmentType, url, altText) {
1083
1121
}
1084
1122
}
1085
1123
1124
+ /**
1125
+ * @param {int } timestamp
1126
+ */
1127
+ function formatTimestamp ( timestamp ) {
1128
+ const userTimeZone = Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ;
1129
+ return DateTime . fromSeconds ( timestamp , { zone : userTimeZone } )
1130
+ . toLocaleString ( DateTime . DATETIME_FULL_WITH_SECONDS ) ;
1131
+ }
1132
+
1086
1133
/**
1087
1134
* @param {URL } sourceUrl
1088
1135
* @param {URL } destinationUrl
0 commit comments