verify.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. const {randomBytes} = require('crypto');
  2. const {MessageEmbed} = require('discord.js');
  3. var db = require('../util/database.js');
  4. var verify = require('../functions/verify.js');
  5. const {oauthVerify, allowDelete, escapeFormatting} = require('../util/functions.js');
  6. /**
  7. * Processes the "verify" command.
  8. * @param {import('../util/i18n.js')} lang - The user language.
  9. * @param {import('discord.js').Message} msg - The Discord message.
  10. * @param {String[]} args - The command arguments.
  11. * @param {String} line - The command as plain text.
  12. * @param {import('../util/wiki.js')} wiki - The wiki for the message.
  13. */
  14. function cmd_verify(lang, msg, args, line, wiki) {
  15. if ( !msg.channel.isGuild() || msg.defaultSettings ) return this.LINK(lang, msg, line, wiki);
  16. if ( !msg.guild.me.permissions.has('MANAGE_ROLES') ) {
  17. if ( msg.isAdmin() ) {
  18. console.log( msg.guild.id + ': Missing permissions - MANAGE_ROLES' );
  19. msg.replyMsg( lang.get('general.missingperm') + ' `MANAGE_ROLES`' );
  20. }
  21. else if ( !msg.onlyVerifyCommand ) this.LINK(lang, msg, line, wiki);
  22. return;
  23. }
  24. db.query( 'SELECT logchannel, flags, onsuccess, onmatch, role, editcount, postcount, usergroup, accountage, rename FROM verification LEFT JOIN verifynotice ON verification.guild = verifynotice.guild WHERE verification.guild = $1 AND channel LIKE $2 ORDER BY configid ASC', [msg.guild.id, '%|' + msg.channel.id + '|%'] ).then( ({rows}) => {
  25. if ( !rows.length ) {
  26. if ( msg.onlyVerifyCommand ) return;
  27. return msg.replyMsg( lang.get('verify.missing') + ( msg.isAdmin() ? '\n`' + ( patreons[msg.guild.id] || process.env.prefix ) + 'verification`' : '' ) );
  28. }
  29. if ( wiki.hasOAuth2() && process.env.dashboard ) {
  30. let oauth = [wiki.hostname + wiki.pathname.slice(0, -1)];
  31. if ( wiki.isWikimedia() ) oauth.push('wikimedia');
  32. if ( wiki.isMiraheze() ) oauth.push('miraheze');
  33. if ( process.env['oauth_' + ( oauth[1] || oauth[0] )] && process.env['oauth_' + ( oauth[1] || oauth[0] ) + '_secret'] ) {
  34. let state = `${oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
  35. while ( oauthVerify.has(state) ) {
  36. state = `${oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
  37. }
  38. oauthVerify.set(state, {
  39. state, wiki: wiki.href,
  40. channel: msg.channel,
  41. user: msg.author.id
  42. });
  43. msg.client.shard.send({id: 'verifyUser', state});
  44. let oauthURL = wiki + 'rest.php/oauth2/authorize?' + new URLSearchParams({
  45. response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
  46. client_id: process.env['oauth_' + ( oauth[1] || oauth[0] )], state
  47. }).toString();
  48. return msg.member.send( lang.get('verify.oauth_message_dm', escapeFormatting(msg.guild.name)) + '\n<' + oauthURL + '>', {
  49. components: [
  50. {
  51. type: 1,
  52. components: [
  53. {
  54. type: 2,
  55. style: 5,
  56. label: lang.get('verify.oauth_button'),
  57. emoji: {id: null, name: '🔗'},
  58. url: oauthURL,
  59. disabled: false
  60. }
  61. ]
  62. }
  63. ]
  64. } ).then( message => {
  65. msg.reactEmoji('📩');
  66. allowDelete(message, msg.author.id);
  67. msg.delete({timeout: 60000, reason: lang.get('verify.footer')}).catch(log_error);
  68. }, error => {
  69. if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
  70. return msg.replyMsg( lang.get('verify.oauth_private') );
  71. }
  72. log_error(error);
  73. msg.reactEmoji('error');
  74. } );
  75. }
  76. }
  77. var username = args.join(' ').replace( /_/g, ' ' ).trim().replace( /^<\s*(.*)\s*>$/, '$1' ).replace( /^@/, '' ).split('#')[0].substring(0, 250).trim();
  78. if ( /^(?:https?:)?\/\/([a-z\d-]{1,50})\.(?:gamepedia\.com\/|(?:fandom\.com|wikia\.org)\/(?:[a-z-]{1,8}\/)?(?:wiki\/)?)/.test(username) ) {
  79. username = decodeURIComponent( username.replace( /^(?:https?:)?\/\/([a-z\d-]{1,50})\.(?:gamepedia\.com\/|(?:fandom\.com|wikia\.org)\/(?:[a-z-]{1,8}\/)?(?:wiki\/)?)/, '' ) );
  80. }
  81. if ( wiki.isGamepedia() ) username = username.replace( /^userprofile\s*:\s*/i, '' );
  82. if ( !username.trim() ) {
  83. args[0] = line.split(' ')[0];
  84. if ( args[0] === 'verification' ) args[0] = ( lang.localNames.verify || 'verify' );
  85. return this.help(lang, msg, args, line, wiki);
  86. }
  87. msg.reactEmoji('⏳').then( reaction => {
  88. verify(lang, msg.channel, msg.member, username, wiki, rows).then( result => {
  89. if ( result.oauth.length ) {
  90. let state = `${result.oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
  91. while ( oauthVerify.has(state) ) {
  92. state = `${result.oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
  93. }
  94. oauthVerify.set(state, {
  95. state, wiki: wiki.href,
  96. channel: msg.channel,
  97. user: msg.author.id
  98. });
  99. msg.client.shard.send({id: 'verifyUser', state});
  100. let oauthURL = wiki + 'rest.php/oauth2/authorize?' + new URLSearchParams({
  101. response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
  102. client_id: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] )], state
  103. }).toString();
  104. msg.member.send( lang.get('verify.oauth_message_dm', escapeFormatting(msg.guild.name)) + '\n<' + oauthURL + '>', {
  105. components: [
  106. {
  107. type: 1,
  108. components: [
  109. {
  110. type: 2,
  111. style: 5,
  112. label: lang.get('verify.oauth_button'),
  113. emoji: {id: null, name: '🔗'},
  114. url: oauthURL,
  115. disabled: false
  116. }
  117. ]
  118. }
  119. ]
  120. } ).then( message => {
  121. msg.reactEmoji('📩');
  122. allowDelete(message, msg.author.id);
  123. msg.delete({timeout: 60000, reason: lang.get('verify.footer')}).catch(log_error);
  124. }, error => {
  125. if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
  126. return msg.replyMsg( lang.get('verify.oauth_private') );
  127. }
  128. log_error(error);
  129. msg.reactEmoji('error');
  130. } );
  131. }
  132. else if ( result.reaction ) msg.reactEmoji(result.reaction);
  133. else {
  134. var options = {embed: result.embed, components: []};
  135. if ( result.add_button ) options.components.push({
  136. type: 1,
  137. components: [
  138. {
  139. type: 2,
  140. style: 1,
  141. label: lang.get('verify.button_again'),
  142. emoji: {id: null, name: '🔂'},
  143. custom_id: 'verify_again',
  144. disabled: false
  145. }
  146. ]
  147. });
  148. if ( result.send_private ) {
  149. let dmEmbed = new MessageEmbed(options.embed);
  150. dmEmbed.fields.forEach( field => {
  151. field.value.replace( /<@&(\d+)>/g, (mention, id) => {
  152. if ( !msg.guild.roles.cache.has(id) ) return mention;
  153. return '@' + msg.guild.roles.cache.get(id)?.name;
  154. } );
  155. } );
  156. msg.member.send( msg.channel.toString() + '; ' + result.content, {embed: dmEmbed, components: []} ).then( message => {
  157. msg.reactEmoji('📩');
  158. allowDelete(message, msg.author.id);
  159. msg.delete({timeout: 60000, reason: lang.get('verify.footer')}).catch(log_error);
  160. }, error => {
  161. if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
  162. return msg.replyMsg( result.content, options, false, false );
  163. }
  164. log_error(error);
  165. msg.reactEmoji('error');
  166. } );
  167. if ( result.logging.channel && msg.guild.channels.cache.has(result.logging.channel) ) {
  168. msg.guild.channels.cache.get(result.logging.channel).send(result.logging.content, {
  169. embed: result.logging.embed,
  170. allowedMentions: {parse: []}
  171. }).catch(log_error);
  172. }
  173. }
  174. else msg.replyMsg( result.content, options, false, false ).then( message => {
  175. if ( !result.logging.channel || !msg.guild.channels.cache.has(result.logging.channel) ) return;
  176. if ( message ) {
  177. if ( result.logging.embed ) result.logging.embed.addField(message.url, '<#' + msg.channel.id + '>');
  178. else result.logging.content += '\n<#' + msg.channel.id + '> – <' + message.url + '>';
  179. }
  180. msg.guild.channels.cache.get(result.logging.channel).send(result.logging.content, {
  181. embed: result.logging.embed,
  182. allowedMentions: {parse: []}
  183. }).catch(log_error);
  184. } );
  185. }
  186. if ( reaction ) reaction.removeEmoji();
  187. }, error => {
  188. console.log( '- Error during the verifications: ' + error );
  189. msg.replyMsg( lang.get('verify.error_reply'), {}, false, false ).then( message => {
  190. if ( message ) message.reactEmoji('error');
  191. } );
  192. } );
  193. } );
  194. }, dberror => {
  195. console.log( '- Error while getting the verifications: ' + dberror );
  196. msg.replyMsg( lang.get('verify.error_reply'), {}, false, false ).then( message => {
  197. if ( message ) message.reactEmoji('error');
  198. } );
  199. } );
  200. }
  201. module.exports = {
  202. name: 'verify',
  203. everyone: true,
  204. pause: false,
  205. owner: false,
  206. run: cmd_verify
  207. };