You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

506 line
11 KiB

  1. let bcrypt = require('bcrypt-nodejs');
  2. let messages = require('../misc/messages');
  3. let skins = require('../config/skins');
  4. let roles = require('../config/roles');
  5. let profanities = require('../misc/profanities');
  6. let fixes = require('../fixes/fixes');
  7. let loginRewards = require('../config/loginRewards');
  8. let mail = require('../mail/mail');
  9. let scheduler = require('../misc/scheduler');
  10. let spirits = require('../config/spirits');
  11. module.exports = {
  12. type: 'auth',
  13. username: null,
  14. charname: null,
  15. characters: {},
  16. characterList: [],
  17. stash: null,
  18. accountInfo: null,
  19. customChannels: [],
  20. play: function (data) {
  21. if (!this.username)
  22. return;
  23. let character = this.characters[data.data.name];
  24. if (!character)
  25. return;
  26. if (character.permadead)
  27. return;
  28. character.stash = this.stash;
  29. character.account = this.username;
  30. this.charname = character.name;
  31. this.checkLoginReward(data, character);
  32. cons.modifyPlayerCount(1);
  33. },
  34. checkLoginReward: function (data, character) {
  35. let accountInfo = this.accountInfo;
  36. let time = scheduler.getTime();
  37. let lastLogin = accountInfo.lastLogin;
  38. if (!lastLogin || lastLogin.day !== time.day) {
  39. let daysSkipped = 1;
  40. if (lastLogin) {
  41. if (time.day > lastLogin.day)
  42. daysSkipped = time.day - lastLogin.day;
  43. else {
  44. let daysInMonth = scheduler.daysInMonth(lastLogin.month);
  45. daysSkipped = (daysInMonth - lastLogin.day) + time.day;
  46. for (let i = lastLogin.month + 1; i < time.month - 1; i++)
  47. daysSkipped += scheduler.daysInMonth(i);
  48. }
  49. }
  50. if (daysSkipped === 1) {
  51. accountInfo.loginStreak++;
  52. if (accountInfo.loginStreak > 21)
  53. accountInfo.loginStreak = 21;
  54. } else {
  55. accountInfo.loginStreak -= (daysSkipped - 1);
  56. if (accountInfo.loginStreak < 1)
  57. accountInfo.loginStreak = 1;
  58. }
  59. let rewards = loginRewards.generate(accountInfo.loginStreak);
  60. mail.sendMail(character.name, rewards, this.onSendRewards.bind(this, data, character));
  61. } else
  62. this.onSendRewards(data, character);
  63. accountInfo.lastLogin = time;
  64. },
  65. onSendRewards: async function (data, character) {
  66. //Bit of a hack. Rethink doesn't havve a busy list
  67. if (mail.busy)
  68. delete mail.busy[character.name];
  69. await io.setAsync({
  70. key: this.username,
  71. table: 'accountInfo',
  72. value: this.accountInfo,
  73. serialize: true
  74. });
  75. this.obj.player.sessionStart = +new Date();
  76. this.obj.player.spawn(character, data.callback);
  77. let prophecies = this.obj.prophecies ? this.obj.prophecies.simplify().list : [];
  78. await leaderboard.setLevel(character.name, this.obj.stats.values.level, prophecies);
  79. },
  80. doSave: async function (callback) {
  81. const simple = this.obj.getSimple(true, true);
  82. simple.components.spliceWhere(f => (f.type === 'stash'));
  83. await io.setAsync({
  84. key: this.charname,
  85. table: 'character',
  86. value: simple,
  87. clean: true,
  88. serialize: true
  89. });
  90. await io.setAsync({
  91. key: this.username,
  92. table: 'stash',
  93. value: this.obj.stash.serialize(),
  94. clean: true,
  95. serialize: true
  96. });
  97. if (callback)
  98. callback();
  99. },
  100. simplify: function () {
  101. return {
  102. type: 'auth',
  103. username: this.username,
  104. charname: this.charname,
  105. skins: this.skins
  106. };
  107. },
  108. getCharacterList: async function (data) {
  109. if (!this.username)
  110. return;
  111. this.characterList = await io.getAsync({
  112. key: this.username,
  113. table: 'characterList',
  114. isArray: true
  115. });
  116. let res = this.characterList.map(c => ({
  117. name: c.name ? c.name : c,
  118. level: leaderboard.getLevel(c.name ? c.name : c)
  119. }));
  120. data.callback(res);
  121. },
  122. getCharacter: async function (data) {
  123. let charName = data.data.name;
  124. if (!this.characterList.some(c => (c.name === charName || c === charName)))
  125. return;
  126. let character = await io.getAsync({
  127. key: charName,
  128. table: 'character',
  129. clean: true
  130. });
  131. fixes.fixCharacter(character);
  132. character.cell = skins.getCell(character.skinId);
  133. character.sheetName = skins.getSpritesheet(character.skinId);
  134. this.characters[charName] = character;
  135. await this.getCustomChannels(character);
  136. await this.getStash();
  137. this.verifySkin(character);
  138. data.callback(character);
  139. },
  140. getCustomChannels: async function (character) {
  141. this.customChannels = await io.getAsync({
  142. key: character.name,
  143. table: 'customChannels',
  144. isArray: true
  145. });
  146. let social = character.components.find(c => (c.type === 'social'));
  147. this.customChannels = fixes.fixCustomChannels(this.customChannels);
  148. if (social)
  149. social.customChannels = this.customChannels;
  150. },
  151. getStash: async function (data, character) {
  152. this.stash = await io.getAsync({
  153. key: this.username,
  154. table: 'stash',
  155. isArray: true,
  156. clean: true
  157. });
  158. fixes.fixStash(this.stash);
  159. },
  160. getSkins: async function (character) {
  161. this.skins = await io.getAsync({
  162. key: this.username,
  163. table: 'skins',
  164. isArray: true
  165. });
  166. fixes.fixSkins(this.username, this.skins);
  167. },
  168. getSkinList: function (msg) {
  169. let list = [...this.skins, ...roles.getSkins(this.username)];
  170. let skinList = skins.getSkinList(list);
  171. msg.callback(skinList);
  172. },
  173. saveSkin: async function (skinId) {
  174. if (!this.skins) {
  175. this.getSkins({
  176. callback: this.saveSkin.bind(this, skinId)
  177. });
  178. return;
  179. }
  180. this.skins.push(skinId);
  181. await io.setAsync({
  182. key: this.username,
  183. table: 'skins',
  184. value: this.skins,
  185. serialize: true
  186. });
  187. },
  188. onSaveSkin: function () {
  189. },
  190. verifySkin: function (character) {
  191. let list = [...this.skins, ...roles.getSkins(this.username)];
  192. let skinList = skins.getSkinList(list);
  193. if (!skinList.some(s => (s.id === character.skinId))) {
  194. character.skinId = '1.0';
  195. character.cell = skins.getCell(character.skinId);
  196. character.sheetName = skins.getSpritesheet(character.skinId);
  197. }
  198. },
  199. doesOwnSkin: function (skinId) {
  200. return [...this.skins, ...roles.getSkins(this.username)].some(s => s === skinId || s === '*');
  201. },
  202. login: async function (msg) {
  203. let credentials = msg.data;
  204. if (credentials.username === '' || credentials.password === '') {
  205. msg.callback(messages.login.allFields);
  206. return;
  207. }
  208. this.username = credentials.username;
  209. let storedPassword = await io.getAsync({
  210. key: credentials.username,
  211. table: 'login',
  212. noParse: true
  213. });
  214. bcrypt.compare(credentials.password, storedPassword, this.onLogin.bind(this, msg, storedPassword));
  215. },
  216. onLogin: async function (msg, storedPassword, err, compareResult) {
  217. if (!compareResult) {
  218. msg.callback(messages.login.incorrect);
  219. return;
  220. }
  221. this.username = msg.data.username;
  222. cons.logOut(this.obj);
  223. await this.getSkins();
  224. this.accountInfo = await io.getAsync({
  225. key: msg.data.username,
  226. table: 'accountInfo',
  227. noDefault: true
  228. }) || {
  229. loginStreak: 0
  230. };
  231. msg.callback();
  232. },
  233. register: async function (msg) {
  234. let credentials = msg.data;
  235. if ((credentials.username === '') || (credentials.password === '')) {
  236. msg.callback(messages.login.allFields);
  237. return;
  238. }
  239. let illegal = ["'", '"', '/', '(', ')', '[', ']', '{', '}', ':', ';', '<', '>'];
  240. for (let i = 0; i < illegal.length; i++) {
  241. if ((credentials.username.indexOf(illegal[i]) > -1) || (credentials.password.indexOf(illegal[i]) > -1)) {
  242. msg.callback(messages.login.illegal);
  243. return;
  244. }
  245. }
  246. let exists = await io.getAsync({
  247. key: credentials.username,
  248. table: 'login',
  249. noDefault: true,
  250. noParse: true
  251. });
  252. if (exists) {
  253. msg.callback(messages.login.exists);
  254. return;
  255. }
  256. bcrypt.hash(credentials.password, null, null, this.onHashGenerated.bind(this, msg));
  257. },
  258. onHashGenerated: async function (msg, err, hashedPassword) {
  259. await io.setAsync({
  260. key: msg.data.username,
  261. table: 'login',
  262. value: hashedPassword
  263. });
  264. this.accountInfo = {
  265. loginStreak: 0
  266. };
  267. await io.setAsync({
  268. key: msg.data.username,
  269. table: 'characterList',
  270. value: [],
  271. serialize: true
  272. });
  273. this.username = msg.data.username;
  274. cons.logOut(this.obj);
  275. await this.getSkins();
  276. msg.callback();
  277. },
  278. createCharacter: async function (msg) {
  279. let data = msg.data;
  280. let name = data.name;
  281. let error = null;
  282. if (name.length < 3 || name.length > 12)
  283. error = messages.createCharacter.nameLength;
  284. else if (!profanities.isClean(name))
  285. error = messages.login.invalid;
  286. else if (name.indexOf(' ') > -1)
  287. msg.callback(messages.login.invalid);
  288. else if (!spirits.list.includes(data.class))
  289. return;
  290. let nLen = name.length;
  291. for (let i = 0; i < nLen; i++) {
  292. let char = name[i].toLowerCase();
  293. let valid = [
  294. 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
  295. ];
  296. if (!valid.includes(char)) {
  297. error = messages.login.invalid;
  298. break;
  299. }
  300. }
  301. if (error) {
  302. msg.callback(error);
  303. return;
  304. }
  305. let exists = await io.getAsync({
  306. key: name,
  307. table: 'character',
  308. noDefault: true
  309. });
  310. if (exists) {
  311. msg.callback(messages.login.charExists);
  312. return;
  313. }
  314. let obj = this.obj;
  315. extend(obj, {
  316. name: name,
  317. skinId: data.skinId,
  318. class: data.class,
  319. cell: skins.getCell(data.skinId),
  320. sheetName: skins.getSpritesheet(data.skinId),
  321. x: null,
  322. y: null
  323. });
  324. let simple = this.obj.getSimple(true);
  325. this.verifySkin(simple);
  326. simple.components.push({
  327. type: 'prophecies',
  328. list: data.prophecies || []
  329. }, {
  330. type: 'social',
  331. customChannels: this.customChannels
  332. });
  333. await io.setAsync({
  334. key: name,
  335. table: 'character',
  336. value: simple,
  337. serialize: true
  338. });
  339. this.characters[name] = simple;
  340. this.characterList.push(name);
  341. await io.setAsync({
  342. key: this.username,
  343. table: 'characterList',
  344. value: this.characterList,
  345. serialize: true
  346. });
  347. this.play({
  348. data: {
  349. name: name
  350. },
  351. callback: msg.callback
  352. });
  353. },
  354. deleteCharacter: async function (msg) {
  355. let data = msg.data;
  356. if ((!data.name) || (!this.username))
  357. return;
  358. if (!this.characterList.some(c => ((c.name === data.name) || (c === data.name)))) {
  359. msg.callback([]);
  360. return;
  361. }
  362. await io.deleteAsync({
  363. key: data.name,
  364. table: 'character'
  365. });
  366. let name = data.name;
  367. this.characterList.spliceWhere(c => (c.name === name || c === name));
  368. let characterList = this.characterList
  369. .map(c => ({
  370. name: c.name ? c.name : c,
  371. level: leaderboard.getLevel(c.name ? c.name : c)
  372. }));
  373. await io.setAsync({
  374. key: this.username,
  375. table: 'characterList',
  376. value: characterList,
  377. serialize: true
  378. });
  379. await leaderboard.deleteCharacter(name);
  380. let result = this.characterList
  381. .map(c => ({
  382. name: c.name ? c.name : c,
  383. level: leaderboard.getLevel(c.name ? c.name : c)
  384. }));
  385. msg.callback(result);
  386. },
  387. permadie: function () {
  388. this.obj.permadead = true;
  389. this.doSave(this.onPermadie.bind(this));
  390. },
  391. onPermadie: function () {
  392. process.send({
  393. method: 'object',
  394. serverId: this.obj.serverId,
  395. obj: {
  396. dead: true
  397. }
  398. });
  399. }
  400. };