Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
3kh0
GitHub Repository: 3kh0/3kh0.github.io-replit
Path: blob/main/assets/webrtc-ip.js
617 views
1
/*
2
* This file is the entire script combined in working order.
3
* Copyright 2021 © Joey Malvinni
4
* License: MIT
5
*/
6
7
// [---------------------------------------------------------------------------]
8
// File: ip_validator.js
9
10
/*
11
* This module validates the two types of IP addresses.
12
* Copyright 2021 © Joey Malvinni
13
* License: MIT
14
*/
15
16
// The function that checks if the given IPv4 address is valid.
17
function is_ipv4(ip){
18
return regex_v4.test(ip);
19
};
20
21
// Checks if the IPv6 address is valid.
22
function is_ipv6(ip){
23
return regex_v6.test(ip);
24
};
25
26
// Simple IP regex that works on both IPv6 and IPv4
27
var simpleIPRegex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g;
28
29
// IPv4 regex used to determine whether an IP is IPv4 or not.
30
let regex_v4 = /((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])/;
31
32
// The IPv6 regex used when determining an IPv6 address.
33
let regex_v6 = /((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))/;
34
35
// Exporting the two regexes in an array to be used in the main detector.
36
let ip_regex_array = [regex_v6, regex_v4]
37
38
39
// [---------------------------------------------------------------------------]
40
// File: peer_conn.js
41
42
/*
43
* This module provides the main WebRTC functions that return IP addresses from the STUN request.
44
* Copyright 2021 © Joey Malvinni
45
* License: MIT
46
*/
47
48
49
function peer(callback){
50
// Creating the peer connection.
51
var WebRTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
52
// Initializing the connection.
53
var createdConnection;
54
55
// Main start function.
56
function start(){
57
// Creating the actual connection.
58
createConnection()
59
// Log the STUN request.
60
createStunRequest()
61
};
62
63
// Stop function to reset the connection.
64
function stop(){
65
// Checking if the connection has been created or not.
66
if (createdConnection) {
67
// Attempt to close it, if RTCPeerConnection.close() is not supported, remove the event listeners.
68
try {
69
createdConnection.close();
70
} finally {
71
createdConnection.onicecandidate = () => {};
72
createdConnection = null;
73
};
74
};
75
};
76
77
// Function that makes the connection request to Google's STUN server
78
function createConnection(){
79
let iceServers = [{
80
urls: 'stun:stun.l.google.com:19302'
81
}];
82
// Creating the connection with the STUN server.
83
createdConnection = new WebRTCPeerConnection({ iceServers });
84
// Handling the ICE candidate event.
85
createdConnection.onicecandidate = (data) => handleCandidates(data);
86
// Creation of the fake data channel.
87
createdConnection.createDataChannel('fake_data_channel');
88
};
89
90
// Function that creates the STUN request offer needed to get the IPs.
91
function createStunRequest(){
92
// Create the offer that exposes the IP addresses.
93
return createdConnection.createOffer().then(sdp => createdConnection.setLocalDescription(sdp));
94
};
95
96
// Handling the onIceCandidate event.
97
function handleCandidates(ice){
98
// Checking if the ICE candidate lines given are valid.
99
if (ice && ice.candidate && ice.candidate.candidate) {
100
// Returning the IPs to the main function.
101
callback(ice && ice.candidate && ice.candidate.candidate);
102
};
103
};
104
105
// Returning the main functions needed.
106
return {
107
start,
108
stop,
109
createConnection,
110
createStunRequest,
111
handleCandidates
112
};
113
};
114
115
// [---------------------------------------------------------------------------]
116
// File: public_ip.js
117
118
/*
119
* This module provides the worker functions that return the public IP addresses.
120
* Copyright 2021 © Joey Malvinni
121
* License: MIT
122
*/
123
124
125
function publicIPs(timer){
126
// Timing validation.
127
if(timer) if(timer < 100) throw new Error('Custom timeout cannot be under 100 milliseconds.');
128
129
// IPs is the final array of all valid IPs found.
130
var IPs = [];
131
// Creating the peer connection request while handling the callback event.
132
var peerConn = peer(handleIceCandidates);
133
134
function getIps(){
135
// Returning a promise.
136
return new Promise(function(resolve, reject) {
137
// Starting the peer connection.
138
peerConn.start();
139
// Setting the timer.
140
setTimeout(() => {
141
// Checking if the IP array exists.
142
if(!IPs || IPs === []){
143
// Rejecting the error
144
reject('No IP addresses were found.')
145
} else {
146
// Return the unique IP addresses in an array.
147
resolve(unique(IPs.flat(Infinity)))
148
};
149
// reset the peer connection.
150
reset();
151
// Set the Timeout to the custom timer, default to 500 milliseconds.
152
}, timer || 500);
153
});
154
};
155
156
function handleIceCandidates(ip){
157
var array = [];
158
// Looping over the two regexs for IPv6 and IPv4
159
for(let regex of ip_regex_array){
160
let arr = [];
161
// Lutting all of the strings that match either IP format in an array
162
let possible_ips_array = regex.exec(ip)
163
if(possible_ips_array){
164
// Looping over that array
165
for(let i = 0; i < possible_ips_array.length; i++){
166
// Checking if the "IP" is valid
167
if(is_ipv4(possible_ips_array[i]) || is_ipv6(possible_ips_array[i])){
168
arr.push(possible_ips_array[i])
169
};
170
};
171
array.push(arr);
172
};
173
};
174
// Final function that does more checks to determine the array's validity,
175
// Also flattens the array to remove extraneous sub-arrays.
176
push(array.flat(Infinity))
177
};
178
179
function push(ip){
180
// Checks if the IP addresses givin are already in the array.
181
if(!IPs.includes(ip)){
182
IPs.push(unique(ip.flat(Infinity)));
183
};
184
};
185
186
function reset(){
187
// Stops the peer connection to the STUN server.
188
peerConn.stop()
189
};
190
// Use this to only return unique IP addresses.
191
function unique(a) {
192
return Array.from(new Set(a));
193
};
194
195
return getIps();
196
};
197
198
// [---------------------------------------------------------------------------]
199
// File: index.js
200
201
/*
202
* This module combines all of the worker modules into the main functions that get exported.
203
* Copyright 2021 © Joey Malvinni
204
* License: MIT
205
*/
206
207
// Categorizes the IPs by IP, type, and IPv4.
208
function getIPTypes(timer){
209
// Returning the result as a promise.
210
return new Promise(function(resolve, reject) {
211
// Final array
212
let finalIpArray = []
213
// Getting the raw IPs in an array.
214
publicIPs(timer).then((ips)=>{
215
// Looping over each IP.
216
ips.forEach(ip => {
217
if (ip.match(/^(192\.168\.|169\.254\.|10\.|172\.(1[6-9]|2\d|3[01]))/)) {
218
// The IP is private.
219
finalIpArray.push({ ip: ip, type: 'private', IPv4: true })
220
} else if (ip.match(/((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))/)) {
221
// The IP is an IPv6 address.
222
finalIpArray.push({ ip: ip, type: 'IPv6', IPv4: false })
223
} else {
224
// Assume the IP is public.
225
finalIpArray.push({ ip: ip, type: 'public', IPv4: true })
226
}
227
})
228
// Resolving the promise.
229
resolve(finalIpArray)
230
}).catch(reject)
231
})
232
}
233
234
// Filters out IPv4 addresses.
235
function getIPv4(timer) {
236
return getIPTypes(timer).then(ips => {
237
// Filters the IP by IPv4.
238
const ip = ips.filter(ip => ip.IPv4);
239
// Loops over each object and extracts the IP.
240
for(let i = 0; i < ip.length; i++){
241
ip[i] = ip[i].ip
242
}
243
// Returns undefined if the array is empty.
244
return ip ? ip : '';
245
});
246
}
247
248
// Filters out IPv6 addresses.
249
function getIPv6(timer) {
250
// Getting the IPs by type.
251
return getIPTypes(timer).then(ips => {
252
// Filtering the IPs by IPv6.
253
const ip = ips.filter(ip => ip.type === 'IPv6');
254
// Extracting the IPs
255
for(let i = 0; i < ip.length; i++){
256
// Removing all other data from the object.
257
ip[i] = ip[i].ip
258
}
259
// Returning the IP or undefined.
260
return ip ? ip.ip : '';
261
});
262
}
263
264
// Returns all of the functions in an object, default to getting all of the IPs without any filtering applied.
265
function getIPs(timer){
266
return Object.assign(
267
publicIPs(timer), {
268
types: getIPTypes,
269
public: publicIPs,
270
IPv4: getIPv4,
271
IPv6: getIPv6,
272
}
273
)
274
};
275