2 const root
= module
.exports
;
3 const net
= require("net");
4 const crypto
= require("crypto");
6 root
.isValidChannelName = function (name
) {
7 return name
.match(/^[\w-]{1,30}$/);
10 root
.isValidUserName = function (name
) {
11 return name
.match(/^[\w-]{1,20}$/);
14 root
.isValidEmail = function (email
) {
15 if (typeof email
!== "string") {
19 if (email
.length
> 255) {
23 if (!email
.match(/^[^@]+?@[^@]+$/)) {
27 if (email
.match(/^[^@]+?@(localhost|127\.0\.0\.1)$/)) {
34 root
.randomSalt = function (length
) {
35 var chars
= "abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
36 + "0123456789!@#$%^&*_+=~";
38 for(var i
= 0; i
< length
; i
++) {
39 salt
.push(chars
[parseInt(Math
.random()*chars
.length
)]);
44 root
.getIPRange = function (ip
) {
46 return root
.expandIPv6(ip
)
47 .replace(/((?:[0-9a-f]{4}:){3}[0-9a-f]{4}):(?:[0-9a-f]{4}:){3}[0-9a-f]{4}/, "$1");
49 return ip
.replace(/((?:[0-9]+\.){2}[0-9]+)\.[0-9]+/, "$1");
53 root
.getWideIPRange = function (ip
) {
55 return root
.expandIPv6(ip
)
56 .replace(/((?:[0-9a-f]{4}:){2}[0-9a-f]{4}):(?:[0-9a-f]{4}:){4}[0-9a-f]{4}/, "$1");
58 return ip
.replace(/([0-9]+\.[0-9]+)\.[0-9]+\.[0-9]+/, "$1");
62 root
.expandIPv6 = function (ip
) {
63 var result
= "0000:0000:0000:0000:0000:0000:0000:0000".split(":");
64 var parts
= ip
.split("::");
65 var left
= parts
[0].split(":");
67 left
.forEach(function (block
) {
68 while (block
.length
< 4) {
74 if (parts
.length
> 1) {
75 var right
= parts
[1].split(":");
77 right
.forEach(function (block
) {
78 while (block
.length
< 4) {
85 return result
.join(":");
88 root
.formatTime = function (sec
) {
92 sec
= Math
.floor(+sec
);
93 var h
= "", m
= "", s
= "";
96 h
= "" + Math
.floor(sec
/ 3600);
102 m
= "" + Math
.floor(sec
/ 60);
111 return [m
, s
].join(":");
113 return [h
, m
, s
].join(":");
116 root
.parseTime = function (time
) {
117 var parts
= time
.split(":").reverse();
119 // TODO: consider refactoring to remove this suppression
120 /* eslint no-fallthrough: off */
121 switch (parts
.length
) {
123 seconds
+= parseInt(parts
[2]) * 3600;
125 seconds
+= parseInt(parts
[1]) * 60;
127 seconds
+= parseInt(parts
[0]);
135 root
.newRateLimiter = function () {
139 throttle: function (opts
) {
140 if (typeof opts
=== "undefined")
143 var burst
= +opts
.burst
,
144 sustained
= +opts
.sustained
,
145 cooldown
= +opts
.cooldown
;
150 if (isNaN(sustained
))
154 cooldown
= burst
/ sustained
;
156 // Cooled down, allow and clear buffer
157 if (this.lastTime
< Date
.now() - cooldown
*1000) {
159 this.lastTime
= Date
.now();
163 // Haven't reached burst cap yet, allow
164 if (this.count
< burst
) {
166 this.lastTime
= Date
.now();
170 var diff
= Date
.now() - this.lastTime
;
171 if (diff
< 1000/sustained
)
174 this.lastTime
= Date
.now();
180 root
.formatLink = function (id
, type
, _meta
) {
183 return "https://youtu.be/" + id
;
185 return "https://vimeo.com/" + id
;
187 return "https://dailymotion.com/video/" + id
;
191 return "https://livestream.com/" + id
;
193 return "https://twitch.tv/" + id
;
197 return "https://ustream.tv/channel/" + id
;
199 return "https://docs.google.com/file/d/" + id
;
203 return "https://www.smashcast.tv/" + id
;
207 return "https://streamable.com/" + id
;
209 return "https://clips.twitch.tv/" + id
;
217 root
.isLive = function (type
) {
232 root
.sha1 = function (data
) {
236 var shasum
= crypto
.createHash("sha1");
238 return shasum
.digest("hex");
241 root
.cloakIP = function (ip
) {
242 if (ip
.match(/\d+\.\d+(\.\d+)?(\.\d+)?/)) {
243 return cloakIPv4(ip
);
244 } else if (ip
.match(/([0-9a-f]{1,4}:){1,7}[0-9a-f]{1,4}/)) {
245 return cloakIPv6(ip
);
250 function iphash(data
, len
) {
251 var md5
= crypto
.createHash("md5");
253 return md5
.digest("base64").substring(0, len
);
256 function cloakIPv4(ip
) {
257 var parts
= ip
.split(".");
258 var accumulator
= "";
260 parts
= parts
.map(function (segment
, i
) {
261 var part
= iphash(accumulator
+ segment
+ i
, 3);
262 accumulator
+= segment
;
266 while (parts
.length
< 4) parts
.push("*");
267 return parts
.join(".");
270 function cloakIPv6(ip
) {
271 var parts
= ip
.split(":");
273 var accumulator
= "";
275 parts
= parts
.map(function (segment
, i
) {
276 var part
= iphash(accumulator
+ segment
+ i
, 4);
277 accumulator
+= segment
;
281 while (parts
.length
< 4) parts
.push("*");
282 return parts
.join(":");