aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/commands/core/changenick.js
blob: cb6d1d0eeaadaf2bf6e55362f6aa519b0066f0fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
  Description: Allows calling client to change their current nickname
*/

// module support functions
const verifyNickname = (nick) => /^[a-zA-Z0-9_]{1,24}$/.test(nick);

// module main
exports.run = async (core, server, socket, data) => {
  if (server.police.frisk(socket.remoteAddress, 6)) {
    return server.reply({
      cmd: 'warn',
      text: 'You are changing nicknames too fast. Wait a moment before trying again.'
    }, socket);
  }

  // verify user data is string
  if (typeof data.nick !== 'string') {
    return;
  }

  // make sure requested nickname meets standards
  let newNick = data.nick.trim();
  if (!verifyNickname(newNick)) {
    return server.reply({
      cmd: 'warn',
      text: 'Nickname must consist of up to 24 letters, numbers, and underscores'
    }, socket);
  }

  // prevent admin impersonation
  // TODO: prevent mod impersonation
  if (newNick.toLowerCase() == core.config.adminName.toLowerCase()) {
    server.police.frisk(socket.remoteAddress, 4);

    return server.reply({
      cmd: 'warn',
      text: 'You are not the admin, liar!'
    }, socket);
  }

  // find any sockets that have the same nickname
  let userExists = server.findSockets({
    channel: socket.channel,
    nick: (targetNick) => targetNick.toLowerCase() === newNick.toLowerCase()
  });

  // return error if found
  if (userExists.length > 0) {
    // That nickname is already in that channel
    return server.reply({
      cmd: 'warn',
      text: 'Nickname taken'
    }, socket);
  }

  // build join and leave notices
  // TODO: this is a legacy client holdover, name changes in the future will
  //       have thieir own event
  let leaveNotice = {
    cmd: 'onlineRemove',
    nick: socket.nick
  };

  let joinNotice = {
    cmd: 'onlineAdd',
    nick: newNick,
    trip: socket.trip || 'null',
    hash: socket.hash
  };

  // broadcast remove event and join event with new name, this is to support legacy clients and bots
  server.broadcast( leaveNotice, { channel: socket.channel });
  server.broadcast( joinNotice, { channel: socket.channel });

  // notify channel that the user has changed their name
  server.broadcast( {
    cmd: 'info',
    text: `${socket.nick} is now ${newNick}`
  }, { channel: socket.channel });

  // commit change to nickname
  socket.nick = newNick;
};

// module hook functions
exports.initHooks = (server) => {
  server.registerHook('in', 'chat', this.nickCheck, 29);
};

// hooks chat commands checking for /nick
exports.nickCheck = (core, server, socket, payload) => {
  if (typeof payload.text !== 'string') {
    return false;
  }

  if (payload.text.startsWith('/nick')) {
    let input = payload.text.split(' ');

    // If there is no nickname target parameter
    if (input[1] === undefined) {
      server.reply({
        cmd: 'warn',
        text: 'Refer to `/help nick` for instructions on how to use this command.'
      }, socket);

      return false;
    }

    let newNick = input[1].replace(/@/g, '');

    this.run(core, server, socket, {
      cmd: 'changenick',
      nick: newNick
    });

    return false;
  }

  return payload;
};

// module meta
exports.requiredData = ['nick'];
exports.info = {
  name: 'changenick',
  description: 'This will change your current connections nickname',
  usage: `
    API: { cmd: 'changenick', nick: '<new nickname>' }
    Text: /nick <new nickname>`
};