IPinfo 0.1.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,252 @@
1
+ {
2
+ "AD": {"emoji": "🇦🇩","unicode": "U+1F1E6 U+1F1E9"},
3
+ "AE": {"emoji": "🇦🇪","unicode": "U+1F1E6 U+1F1EA"},
4
+ "AF": {"emoji": "🇦🇫","unicode": "U+1F1E6 U+1F1EB"},
5
+ "AG": {"emoji": "🇦🇬","unicode": "U+1F1E6 U+1F1EC"},
6
+ "AI": {"emoji": "🇦🇮","unicode": "U+1F1E6 U+1F1EE"},
7
+ "AL": {"emoji": "🇦🇱","unicode": "U+1F1E6 U+1F1F1"},
8
+ "AM": {"emoji": "🇦🇲","unicode": "U+1F1E6 U+1F1F2"},
9
+ "AO": {"emoji": "🇦🇴","unicode": "U+1F1E6 U+1F1F4"},
10
+ "AQ": {"emoji": "🇦🇶","unicode": "U+1F1E6 U+1F1F6"},
11
+ "AR": {"emoji": "🇦🇷","unicode": "U+1F1E6 U+1F1F7"},
12
+ "AS": {"emoji": "🇦🇸","unicode": "U+1F1E6 U+1F1F8"},
13
+ "AT": {"emoji": "🇦🇹","unicode": "U+1F1E6 U+1F1F9"},
14
+ "AU": {"emoji": "🇦🇺","unicode": "U+1F1E6 U+1F1FA"},
15
+ "AW": {"emoji": "🇦🇼","unicode": "U+1F1E6 U+1F1FC"},
16
+ "AX": {"emoji": "🇦🇽","unicode": "U+1F1E6 U+1F1FD"},
17
+ "AZ": {"emoji": "🇦🇿","unicode": "U+1F1E6 U+1F1FF"},
18
+ "BA": {"emoji": "🇧🇦","unicode": "U+1F1E7 U+1F1E6"},
19
+ "BB": {"emoji": "🇧🇧","unicode": "U+1F1E7 U+1F1E7"},
20
+ "BD": {"emoji": "🇧🇩","unicode": "U+1F1E7 U+1F1E9"},
21
+ "BE": {"emoji": "🇧🇪","unicode": "U+1F1E7 U+1F1EA"},
22
+ "BF": {"emoji": "🇧🇫","unicode": "U+1F1E7 U+1F1EB"},
23
+ "BG": {"emoji": "🇧🇬","unicode": "U+1F1E7 U+1F1EC"},
24
+ "BH": {"emoji": "🇧🇭","unicode": "U+1F1E7 U+1F1ED"},
25
+ "BI": {"emoji": "🇧🇮","unicode": "U+1F1E7 U+1F1EE"},
26
+ "BJ": {"emoji": "🇧🇯","unicode": "U+1F1E7 U+1F1EF"},
27
+ "BL": {"emoji": "🇧🇱","unicode": "U+1F1E7 U+1F1F1"},
28
+ "BM": {"emoji": "🇧🇲","unicode": "U+1F1E7 U+1F1F2"},
29
+ "BN": {"emoji": "🇧🇳","unicode": "U+1F1E7 U+1F1F3"},
30
+ "BO": {"emoji": "🇧🇴","unicode": "U+1F1E7 U+1F1F4"},
31
+ "BQ": {"emoji": "🇧🇶","unicode": "U+1F1E7 U+1F1F6"},
32
+ "BR": {"emoji": "🇧🇷","unicode": "U+1F1E7 U+1F1F7"},
33
+ "BS": {"emoji": "🇧🇸","unicode": "U+1F1E7 U+1F1F8"},
34
+ "BT": {"emoji": "🇧🇹","unicode": "U+1F1E7 U+1F1F9"},
35
+ "BV": {"emoji": "🇧🇻","unicode": "U+1F1E7 U+1F1FB"},
36
+ "BW": {"emoji": "🇧🇼","unicode": "U+1F1E7 U+1F1FC"},
37
+ "BY": {"emoji": "🇧🇾","unicode": "U+1F1E7 U+1F1FE"},
38
+ "BZ": {"emoji": "🇧🇿","unicode": "U+1F1E7 U+1F1FF"},
39
+ "CA": {"emoji": "🇨🇦","unicode": "U+1F1E8 U+1F1E6"},
40
+ "CC": {"emoji": "🇨🇨","unicode": "U+1F1E8 U+1F1E8"},
41
+ "CD": {"emoji": "🇨🇩","unicode": "U+1F1E8 U+1F1E9"},
42
+ "CF": {"emoji": "🇨🇫","unicode": "U+1F1E8 U+1F1EB"},
43
+ "CG": {"emoji": "🇨🇬","unicode": "U+1F1E8 U+1F1EC"},
44
+ "CH": {"emoji": "🇨🇭","unicode": "U+1F1E8 U+1F1ED"},
45
+ "CI": {"emoji": "🇨🇮","unicode": "U+1F1E8 U+1F1EE"},
46
+ "CK": {"emoji": "🇨🇰","unicode": "U+1F1E8 U+1F1F0"},
47
+ "CL": {"emoji": "🇨🇱","unicode": "U+1F1E8 U+1F1F1"},
48
+ "CM": {"emoji": "🇨🇲","unicode": "U+1F1E8 U+1F1F2"},
49
+ "CN": {"emoji": "🇨🇳","unicode": "U+1F1E8 U+1F1F3"},
50
+ "CO": {"emoji": "🇨🇴","unicode": "U+1F1E8 U+1F1F4"},
51
+ "CR": {"emoji": "🇨🇷","unicode": "U+1F1E8 U+1F1F7"},
52
+ "CU": {"emoji": "🇨🇺","unicode": "U+1F1E8 U+1F1FA"},
53
+ "CV": {"emoji": "🇨🇻","unicode": "U+1F1E8 U+1F1FB"},
54
+ "CW": {"emoji": "🇨🇼","unicode": "U+1F1E8 U+1F1FC"},
55
+ "CX": {"emoji": "🇨🇽","unicode": "U+1F1E8 U+1F1FD"},
56
+ "CY": {"emoji": "🇨🇾","unicode": "U+1F1E8 U+1F1FE"},
57
+ "CZ": {"emoji": "🇨🇿","unicode": "U+1F1E8 U+1F1FF"},
58
+ "DE": {"emoji": "🇩🇪","unicode": "U+1F1E9 U+1F1EA"},
59
+ "DJ": {"emoji": "🇩🇯","unicode": "U+1F1E9 U+1F1EF"},
60
+ "DK": {"emoji": "🇩🇰","unicode": "U+1F1E9 U+1F1F0"},
61
+ "DM": {"emoji": "🇩🇲","unicode": "U+1F1E9 U+1F1F2"},
62
+ "DO": {"emoji": "🇩🇴","unicode": "U+1F1E9 U+1F1F4"},
63
+ "DZ": {"emoji": "🇩🇿","unicode": "U+1F1E9 U+1F1FF"},
64
+ "EC": {"emoji": "🇪🇨","unicode": "U+1F1EA U+1F1E8"},
65
+ "EE": {"emoji": "🇪🇪","unicode": "U+1F1EA U+1F1EA"},
66
+ "EG": {"emoji": "🇪🇬","unicode": "U+1F1EA U+1F1EC"},
67
+ "EH": {"emoji": "🇪🇭","unicode": "U+1F1EA U+1F1ED"},
68
+ "ER": {"emoji": "🇪🇷","unicode": "U+1F1EA U+1F1F7"},
69
+ "ES": {"emoji": "🇪🇸","unicode": "U+1F1EA U+1F1F8"},
70
+ "ET": {"emoji": "🇪🇹","unicode": "U+1F1EA U+1F1F9"},
71
+ "FI": {"emoji": "🇫🇮","unicode": "U+1F1EB U+1F1EE"},
72
+ "FJ": {"emoji": "🇫🇯","unicode": "U+1F1EB U+1F1EF"},
73
+ "FK": {"emoji": "🇫🇰","unicode": "U+1F1EB U+1F1F0"},
74
+ "FM": {"emoji": "🇫🇲","unicode": "U+1F1EB U+1F1F2"},
75
+ "FO": {"emoji": "🇫🇴","unicode": "U+1F1EB U+1F1F4"},
76
+ "FR": {"emoji": "🇫🇷","unicode": "U+1F1EB U+1F1F7"},
77
+ "GA": {"emoji": "🇬🇦","unicode": "U+1F1EC U+1F1E6"},
78
+ "GB": {"emoji": "🇬🇧","unicode": "U+1F1EC U+1F1E7"},
79
+ "GD": {"emoji": "🇬🇩","unicode": "U+1F1EC U+1F1E9"},
80
+ "GE": {"emoji": "🇬🇪","unicode": "U+1F1EC U+1F1EA"},
81
+ "GF": {"emoji": "🇬🇫","unicode": "U+1F1EC U+1F1EB"},
82
+ "GG": {"emoji": "🇬🇬","unicode": "U+1F1EC U+1F1EC"},
83
+ "GH": {"emoji": "🇬🇭","unicode": "U+1F1EC U+1F1ED"},
84
+ "GI": {"emoji": "🇬🇮","unicode": "U+1F1EC U+1F1EE"},
85
+ "GL": {"emoji": "🇬🇱","unicode": "U+1F1EC U+1F1F1"},
86
+ "GM": {"emoji": "🇬🇲","unicode": "U+1F1EC U+1F1F2"},
87
+ "GN": {"emoji": "🇬🇳","unicode": "U+1F1EC U+1F1F3"},
88
+ "GP": {"emoji": "🇬🇵","unicode": "U+1F1EC U+1F1F5"},
89
+ "GQ": {"emoji": "🇬🇶","unicode": "U+1F1EC U+1F1F6"},
90
+ "GR": {"emoji": "🇬🇷","unicode": "U+1F1EC U+1F1F7"},
91
+ "GS": {"emoji": "🇬🇸","unicode": "U+1F1EC U+1F1F8"},
92
+ "GT": {"emoji": "🇬🇹","unicode": "U+1F1EC U+1F1F9"},
93
+ "GU": {"emoji": "🇬🇺","unicode": "U+1F1EC U+1F1FA"},
94
+ "GW": {"emoji": "🇬🇼","unicode": "U+1F1EC U+1F1FC"},
95
+ "GY": {"emoji": "🇬🇾","unicode": "U+1F1EC U+1F1FE"},
96
+ "HK": {"emoji": "🇭🇰","unicode": "U+1F1ED U+1F1F0"},
97
+ "HM": {"emoji": "🇭🇲","unicode": "U+1F1ED U+1F1F2"},
98
+ "HN": {"emoji": "🇭🇳","unicode": "U+1F1ED U+1F1F3"},
99
+ "HR": {"emoji": "🇭🇷","unicode": "U+1F1ED U+1F1F7"},
100
+ "HT": {"emoji": "🇭🇹","unicode": "U+1F1ED U+1F1F9"},
101
+ "HU": {"emoji": "🇭🇺","unicode": "U+1F1ED U+1F1FA"},
102
+ "ID": {"emoji": "🇮🇩","unicode": "U+1F1EE U+1F1E9"},
103
+ "IE": {"emoji": "🇮🇪","unicode": "U+1F1EE U+1F1EA"},
104
+ "IL": {"emoji": "🇮🇱","unicode": "U+1F1EE U+1F1F1"},
105
+ "IM": {"emoji": "🇮🇲","unicode": "U+1F1EE U+1F1F2"},
106
+ "IN": {"emoji": "🇮🇳","unicode": "U+1F1EE U+1F1F3"},
107
+ "IO": {"emoji": "🇮🇴","unicode": "U+1F1EE U+1F1F4"},
108
+ "IQ": {"emoji": "🇮🇶","unicode": "U+1F1EE U+1F1F6"},
109
+ "IR": {"emoji": "🇮🇷","unicode": "U+1F1EE U+1F1F7"},
110
+ "IS": {"emoji": "🇮🇸","unicode": "U+1F1EE U+1F1F8"},
111
+ "IT": {"emoji": "🇮🇹","unicode": "U+1F1EE U+1F1F9"},
112
+ "JE": {"emoji": "🇯🇪","unicode": "U+1F1EF U+1F1EA"},
113
+ "JM": {"emoji": "🇯🇲","unicode": "U+1F1EF U+1F1F2"},
114
+ "JO": {"emoji": "🇯🇴","unicode": "U+1F1EF U+1F1F4"},
115
+ "JP": {"emoji": "🇯🇵","unicode": "U+1F1EF U+1F1F5"},
116
+ "KE": {"emoji": "🇰🇪","unicode": "U+1F1F0 U+1F1EA"},
117
+ "KG": {"emoji": "🇰🇬","unicode": "U+1F1F0 U+1F1EC"},
118
+ "KH": {"emoji": "🇰🇭","unicode": "U+1F1F0 U+1F1ED"},
119
+ "KI": {"emoji": "🇰🇮","unicode": "U+1F1F0 U+1F1EE"},
120
+ "KM": {"emoji": "🇰🇲","unicode": "U+1F1F0 U+1F1F2"},
121
+ "KN": {"emoji": "🇰🇳","unicode": "U+1F1F0 U+1F1F3"},
122
+ "KP": {"emoji": "🇰🇵","unicode": "U+1F1F0 U+1F1F5"},
123
+ "KR": {"emoji": "🇰🇷","unicode": "U+1F1F0 U+1F1F7"},
124
+ "KW": {"emoji": "🇰🇼","unicode": "U+1F1F0 U+1F1FC"},
125
+ "KY": {"emoji": "🇰🇾","unicode": "U+1F1F0 U+1F1FE"},
126
+ "KZ": {"emoji": "🇰🇿","unicode": "U+1F1F0 U+1F1FF"},
127
+ "LA": {"emoji": "🇱🇦","unicode": "U+1F1F1 U+1F1E6"},
128
+ "LB": {"emoji": "🇱🇧","unicode": "U+1F1F1 U+1F1E7"},
129
+ "LC": {"emoji": "🇱🇨","unicode": "U+1F1F1 U+1F1E8"},
130
+ "LI": {"emoji": "🇱🇮","unicode": "U+1F1F1 U+1F1EE"},
131
+ "LK": {"emoji": "🇱🇰","unicode": "U+1F1F1 U+1F1F0"},
132
+ "LR": {"emoji": "🇱🇷","unicode": "U+1F1F1 U+1F1F7"},
133
+ "LS": {"emoji": "🇱🇸","unicode": "U+1F1F1 U+1F1F8"},
134
+ "LT": {"emoji": "🇱🇹","unicode": "U+1F1F1 U+1F1F9"},
135
+ "LU": {"emoji": "🇱🇺","unicode": "U+1F1F1 U+1F1FA"},
136
+ "LV": {"emoji": "🇱🇻","unicode": "U+1F1F1 U+1F1FB"},
137
+ "LY": {"emoji": "🇱🇾","unicode": "U+1F1F1 U+1F1FE"},
138
+ "MA": {"emoji": "🇲🇦","unicode": "U+1F1F2 U+1F1E6"},
139
+ "MC": {"emoji": "🇲🇨","unicode": "U+1F1F2 U+1F1E8"},
140
+ "MD": {"emoji": "🇲🇩","unicode": "U+1F1F2 U+1F1E9"},
141
+ "ME": {"emoji": "🇲🇪","unicode": "U+1F1F2 U+1F1EA"},
142
+ "MF": {"emoji": "🇲🇫","unicode": "U+1F1F2 U+1F1EB"},
143
+ "MG": {"emoji": "🇲🇬","unicode": "U+1F1F2 U+1F1EC"},
144
+ "MH": {"emoji": "🇲🇭","unicode": "U+1F1F2 U+1F1ED"},
145
+ "MK": {"emoji": "🇲🇰","unicode": "U+1F1F2 U+1F1F0"},
146
+ "ML": {"emoji": "🇲🇱","unicode": "U+1F1F2 U+1F1F1"},
147
+ "MM": {"emoji": "🇲🇲","unicode": "U+1F1F2 U+1F1F2"},
148
+ "MN": {"emoji": "🇲🇳","unicode": "U+1F1F2 U+1F1F3"},
149
+ "MO": {"emoji": "🇲🇴","unicode": "U+1F1F2 U+1F1F4"},
150
+ "MP": {"emoji": "🇲🇵","unicode": "U+1F1F2 U+1F1F5"},
151
+ "MQ": {"emoji": "🇲🇶","unicode": "U+1F1F2 U+1F1F6"},
152
+ "MR": {"emoji": "🇲🇷","unicode": "U+1F1F2 U+1F1F7"},
153
+ "MS": {"emoji": "🇲🇸","unicode": "U+1F1F2 U+1F1F8"},
154
+ "MT": {"emoji": "🇲🇹","unicode": "U+1F1F2 U+1F1F9"},
155
+ "MU": {"emoji": "🇲🇺","unicode": "U+1F1F2 U+1F1FA"},
156
+ "MV": {"emoji": "🇲🇻","unicode": "U+1F1F2 U+1F1FB"},
157
+ "MW": {"emoji": "🇲🇼","unicode": "U+1F1F2 U+1F1FC"},
158
+ "MX": {"emoji": "🇲🇽","unicode": "U+1F1F2 U+1F1FD"},
159
+ "MY": {"emoji": "🇲🇾","unicode": "U+1F1F2 U+1F1FE"},
160
+ "MZ": {"emoji": "🇲🇿","unicode": "U+1F1F2 U+1F1FF"},
161
+ "NA": {"emoji": "🇳🇦","unicode": "U+1F1F3 U+1F1E6"},
162
+ "NC": {"emoji": "🇳🇨","unicode": "U+1F1F3 U+1F1E8"},
163
+ "NE": {"emoji": "🇳🇪","unicode": "U+1F1F3 U+1F1EA"},
164
+ "NF": {"emoji": "🇳🇫","unicode": "U+1F1F3 U+1F1EB"},
165
+ "NG": {"emoji": "🇳🇬","unicode": "U+1F1F3 U+1F1EC"},
166
+ "NI": {"emoji": "🇳🇮","unicode": "U+1F1F3 U+1F1EE"},
167
+ "NL": {"emoji": "🇳🇱","unicode": "U+1F1F3 U+1F1F1"},
168
+ "NO": {"emoji": "🇳🇴","unicode": "U+1F1F3 U+1F1F4"},
169
+ "NP": {"emoji": "🇳🇵","unicode": "U+1F1F3 U+1F1F5"},
170
+ "NR": {"emoji": "🇳🇷","unicode": "U+1F1F3 U+1F1F7"},
171
+ "NU": {"emoji": "🇳🇺","unicode": "U+1F1F3 U+1F1FA"},
172
+ "NZ": {"emoji": "🇳🇿","unicode": "U+1F1F3 U+1F1FF"},
173
+ "OM": {"emoji": "🇴🇲","unicode": "U+1F1F4 U+1F1F2"},
174
+ "PA": {"emoji": "🇵🇦","unicode": "U+1F1F5 U+1F1E6"},
175
+ "PE": {"emoji": "🇵🇪","unicode": "U+1F1F5 U+1F1EA"},
176
+ "PF": {"emoji": "🇵🇫","unicode": "U+1F1F5 U+1F1EB"},
177
+ "PG": {"emoji": "🇵🇬","unicode": "U+1F1F5 U+1F1EC"},
178
+ "PH": {"emoji": "🇵🇭","unicode": "U+1F1F5 U+1F1ED"},
179
+ "PK": {"emoji": "🇵🇰","unicode": "U+1F1F5 U+1F1F0"},
180
+ "PL": {"emoji": "🇵🇱","unicode": "U+1F1F5 U+1F1F1"},
181
+ "PM": {"emoji": "🇵🇲","unicode": "U+1F1F5 U+1F1F2"},
182
+ "PN": {"emoji": "🇵🇳","unicode": "U+1F1F5 U+1F1F3"},
183
+ "PR": {"emoji": "🇵🇷","unicode": "U+1F1F5 U+1F1F7"},
184
+ "PS": {"emoji": "🇵🇸","unicode": "U+1F1F5 U+1F1F8"},
185
+ "PT": {"emoji": "🇵🇹","unicode": "U+1F1F5 U+1F1F9"},
186
+ "PW": {"emoji": "🇵🇼","unicode": "U+1F1F5 U+1F1FC"},
187
+ "PY": {"emoji": "🇵🇾","unicode": "U+1F1F5 U+1F1FE"},
188
+ "QA": {"emoji": "🇶🇦","unicode": "U+1F1F6 U+1F1E6"},
189
+ "RE": {"emoji": "🇷🇪","unicode": "U+1F1F7 U+1F1EA"},
190
+ "RO": {"emoji": "🇷🇴","unicode": "U+1F1F7 U+1F1F4"},
191
+ "RS": {"emoji": "🇷🇸","unicode": "U+1F1F7 U+1F1F8"},
192
+ "RU": {"emoji": "🇷🇺","unicode": "U+1F1F7 U+1F1FA"},
193
+ "RW": {"emoji": "🇷🇼","unicode": "U+1F1F7 U+1F1FC"},
194
+ "SA": {"emoji": "🇸🇦","unicode": "U+1F1F8 U+1F1E6"},
195
+ "SB": {"emoji": "🇸🇧","unicode": "U+1F1F8 U+1F1E7"},
196
+ "SC": {"emoji": "🇸🇨","unicode": "U+1F1F8 U+1F1E8"},
197
+ "SD": {"emoji": "🇸🇩","unicode": "U+1F1F8 U+1F1E9"},
198
+ "SE": {"emoji": "🇸🇪","unicode": "U+1F1F8 U+1F1EA"},
199
+ "SG": {"emoji": "🇸🇬","unicode": "U+1F1F8 U+1F1EC"},
200
+ "SH": {"emoji": "🇸🇭","unicode": "U+1F1F8 U+1F1ED"},
201
+ "SI": {"emoji": "🇸🇮","unicode": "U+1F1F8 U+1F1EE"},
202
+ "SJ": {"emoji": "🇸🇯","unicode": "U+1F1F8 U+1F1EF"},
203
+ "SK": {"emoji": "🇸🇰","unicode": "U+1F1F8 U+1F1F0"},
204
+ "SL": {"emoji": "🇸🇱","unicode": "U+1F1F8 U+1F1F1"},
205
+ "SM": {"emoji": "🇸🇲","unicode": "U+1F1F8 U+1F1F2"},
206
+ "SN": {"emoji": "🇸🇳","unicode": "U+1F1F8 U+1F1F3"},
207
+ "SO": {"emoji": "🇸🇴","unicode": "U+1F1F8 U+1F1F4"},
208
+ "SR": {"emoji": "🇸🇷","unicode": "U+1F1F8 U+1F1F7"},
209
+ "SS": {"emoji": "🇸🇸","unicode": "U+1F1F8 U+1F1F8"},
210
+ "ST": {"emoji": "🇸🇹","unicode": "U+1F1F8 U+1F1F9"},
211
+ "SV": {"emoji": "🇸🇻","unicode": "U+1F1F8 U+1F1FB"},
212
+ "SX": {"emoji": "🇸🇽","unicode": "U+1F1F8 U+1F1FD"},
213
+ "SY": {"emoji": "🇸🇾","unicode": "U+1F1F8 U+1F1FE"},
214
+ "SZ": {"emoji": "🇸🇿","unicode": "U+1F1F8 U+1F1FF"},
215
+ "TC": {"emoji": "🇹🇨","unicode": "U+1F1F9 U+1F1E8"},
216
+ "TD": {"emoji": "🇹🇩","unicode": "U+1F1F9 U+1F1E9"},
217
+ "TF": {"emoji": "🇹🇫","unicode": "U+1F1F9 U+1F1EB"},
218
+ "TG": {"emoji": "🇹🇬","unicode": "U+1F1F9 U+1F1EC"},
219
+ "TH": {"emoji": "🇹🇭","unicode": "U+1F1F9 U+1F1ED"},
220
+ "TJ": {"emoji": "🇹🇯","unicode": "U+1F1F9 U+1F1EF"},
221
+ "TK": {"emoji": "🇹🇰","unicode": "U+1F1F9 U+1F1F0"},
222
+ "TL": {"emoji": "🇹🇱","unicode": "U+1F1F9 U+1F1F1"},
223
+ "TM": {"emoji": "🇹🇲","unicode": "U+1F1F9 U+1F1F2"},
224
+ "TN": {"emoji": "🇹🇳","unicode": "U+1F1F9 U+1F1F3"},
225
+ "TO": {"emoji": "🇹🇴","unicode": "U+1F1F9 U+1F1F4"},
226
+ "TR": {"emoji": "🇹🇷","unicode": "U+1F1F9 U+1F1F7"},
227
+ "TT": {"emoji": "🇹🇹","unicode": "U+1F1F9 U+1F1F9"},
228
+ "TV": {"emoji": "🇹🇻","unicode": "U+1F1F9 U+1F1FB"},
229
+ "TW": {"emoji": "🇹🇼","unicode": "U+1F1F9 U+1F1FC"},
230
+ "TZ": {"emoji": "🇹🇿","unicode": "U+1F1F9 U+1F1FF"},
231
+ "UA": {"emoji": "🇺🇦","unicode": "U+1F1FA U+1F1E6"},
232
+ "UG": {"emoji": "🇺🇬","unicode": "U+1F1FA U+1F1EC"},
233
+ "UM": {"emoji": "🇺🇲","unicode": "U+1F1FA U+1F1F2"},
234
+ "US": {"emoji": "🇺🇸","unicode": "U+1F1FA U+1F1F8"},
235
+ "UY": {"emoji": "🇺🇾","unicode": "U+1F1FA U+1F1FE"},
236
+ "UZ": {"emoji": "🇺🇿","unicode": "U+1F1FA U+1F1FF"},
237
+ "VA": {"emoji": "🇻🇦","unicode": "U+1F1FB U+1F1E6"},
238
+ "VC": {"emoji": "🇻🇨","unicode": "U+1F1FB U+1F1E8"},
239
+ "VE": {"emoji": "🇻🇪","unicode": "U+1F1FB U+1F1EA"},
240
+ "VG": {"emoji": "🇻🇬","unicode": "U+1F1FB U+1F1EC"},
241
+ "VI": {"emoji": "🇻🇮","unicode": "U+1F1FB U+1F1EE"},
242
+ "VN": {"emoji": "🇻🇳","unicode": "U+1F1FB U+1F1F3"},
243
+ "VU": {"emoji": "🇻🇺","unicode": "U+1F1FB U+1F1FA"},
244
+ "WF": {"emoji": "🇼🇫","unicode": "U+1F1FC U+1F1EB"},
245
+ "WS": {"emoji": "🇼🇸","unicode": "U+1F1FC U+1F1F8"},
246
+ "XK": {"emoji": "🇽🇰","unicode": "U+1F1FD U+1F1F0"},
247
+ "YE": {"emoji": "🇾🇪","unicode": "U+1F1FE U+1F1EA"},
248
+ "YT": {"emoji": "🇾🇹","unicode": "U+1F1FE U+1F1F9"},
249
+ "ZA": {"emoji": "🇿🇦","unicode": "U+1F1FF U+1F1E6"},
250
+ "ZM": {"emoji": "🇿🇲","unicode": "U+1F1FF U+1F1F2"},
251
+ "ZW": {"emoji": "🇿🇼","unicode": "U+1F1FF U+1F1FC"}
252
+ }
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'resolv'
4
+ require 'ipaddr'
5
+
6
+ class IPinfo::IpAddressMatcher
7
+ attr_accessor :required_address
8
+
9
+ @@bogon_list = [
10
+ "0.0.0.0/8",
11
+ "10.0.0.0/8",
12
+ "100.64.0.0/10",
13
+ "127.0.0.0/8",
14
+ "169.254.0.0/16",
15
+ "172.16.0.0/12",
16
+ "192.0.0.0/24",
17
+ "192.0.2.0/24",
18
+ "192.168.0.0/16",
19
+ "198.18.0.0/15",
20
+ "198.51.100.0/24",
21
+ "203.0.113.0/24",
22
+ "224.0.0.0/4",
23
+ "240.0.0.0/4",
24
+ "255.255.255.255/32",
25
+ "::/128",
26
+ "::1/128",
27
+ "::ffff:0:0/96",
28
+ "::/96",
29
+ "100::/64",
30
+ "2001:10::/28",
31
+ "2001:db8::/32",
32
+ "fc00::/7",
33
+ "fe80::/10",
34
+ "fec0::/10",
35
+ "ff00::/8",
36
+ "2002::/24",
37
+ "2002:a00::/24",
38
+ "2002:7f00::/24",
39
+ "2002:a9fe::/32",
40
+ "2002:ac10::/28",
41
+ "2002:c000::/40",
42
+ "2002:c000:200::/40",
43
+ "2002:c0a8::/32",
44
+ "2002:c612::/31",
45
+ "2002:c633:6400::/40",
46
+ "2002:cb00:7100::/40",
47
+ "2002:e000::/20",
48
+ "2002:f000::/20",
49
+ "2002:ffff:ffff::/48",
50
+ "2001::/40",
51
+ "2001:0:a00::/40",
52
+ "2001:0:7f00::/40",
53
+ "2001:0:a9fe::/48",
54
+ "2001:0:ac10::/44",
55
+ "2001:0:c000::/56",
56
+ "2001:0:c000:200::/56",
57
+ "2001:0:c0a8::/48",
58
+ "2001:0:c612::/47",
59
+ "2001:0:c633:6400::/56",
60
+ "2001:0:cb00:7100::/56",
61
+ "2001:0:e000::/36",
62
+ "2001:0:f000::/36",
63
+ "2001:0:ffff:ffff::/64"
64
+ ]
65
+
66
+ def initialize(ip)
67
+ if !ip.index('/').nil? and ip.index('/') > 0
68
+ addr_mask = ip.split('/')
69
+ ip = addr_mask[0]
70
+ end
71
+
72
+ @required_address = parseAddress(ip)
73
+ end
74
+
75
+ def parseAddress(ip)
76
+ begin
77
+ Resolv.getaddress ip
78
+ rescue Resolv::ResolvError => e
79
+ pp e
80
+ end
81
+ end
82
+
83
+ def matches
84
+ for bogon in @@bogon_list do
85
+ if bogon.include? required_address
86
+ return true
87
+ end
88
+ end
89
+
90
+ false
91
+ end
92
+ end
data/lib/ipinfo/mod.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IPinfo
4
+ end
@@ -3,18 +3,17 @@
3
3
  require 'ipaddr'
4
4
  require 'json'
5
5
 
6
- module IPinfo
7
- class Response
8
-
6
+ class IPinfo::Response
9
7
  attr_reader :all
10
8
 
11
9
  def initialize(response)
12
- @all = response
10
+ @all = response
11
+
12
+ @all.each do |name, value|
13
+ instance_variable_set("@#{name}", value)
13
14
 
14
- @all.each do |name, value|
15
- instance_variable_set("@#{name}", value)
16
- self.class.send(:attr_accessor, name)
17
- end
15
+ c = class << self; self end
16
+ c.send(:attr_accessor, name)
17
+ end
18
18
  end
19
- end
20
19
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module IPinfo
2
- VERSION = "0.1.2"
4
+ VERSION = '1.1.0'
3
5
  end
data/lib/ipinfo.rb CHANGED
@@ -8,82 +8,198 @@ require 'ipinfo/errors'
8
8
  require 'ipinfo/response'
9
9
  require 'ipinfo/version'
10
10
  require 'json'
11
+ require_relative 'ipinfo/ipAddressMatcher'
11
12
 
12
13
  module IPinfo
13
- DEFAULT_CACHE_MAXSIZE = 4096
14
- DEFAULT_CACHE_TTL = 60 * 60 * 24
15
- DEFAULT_COUNTRY_FILE = File.join(File.dirname(__FILE__), 'ipinfo/countries.json')
16
- RATE_LIMIT_MESSAGE = "To increase your limits, please review our paid plans at https://ipinfo.io/pricing"
17
-
18
- class << self
19
- def create(access_token=nil, settings={})
20
- IPinfo.new(access_token, settings)
14
+ DEFAULT_CACHE_MAXSIZE = 4096
15
+ DEFAULT_CACHE_TTL = 60 * 60 * 24
16
+ DEFAULT_COUNTRY_FILE = File.join(File.dirname(__FILE__),
17
+ 'ipinfo/countries.json')
18
+ DEFAULT_EU_COUNTRIES_FILE = File.join(File.dirname(__FILE__),
19
+ 'ipinfo/eu.json')
20
+ DEFAULT_COUNTRIES_FLAG_FILE = File.join(File.dirname(__FILE__),
21
+ 'ipinfo/flags.json')
22
+ DEFAULT_COUNTRIES_CURRENCIES_FILE = File.join(File.dirname(__FILE__),
23
+ 'ipinfo/currency.json')
24
+ DEFAULT_CONTINENT_FILE = File.join(File.dirname(__FILE__),
25
+ 'ipinfo/continent.json')
26
+ RATE_LIMIT_MESSAGE = 'To increase your limits, please review our ' \
27
+ 'paid plans at https://ipinfo.io/pricing'
28
+ # Base URL to get country flag image link.
29
+ # "PK" -> "https://cdn.ipinfo.io/static/images/countries-flags/PK.svg"
30
+ COUNTRY_FLAGS_URL = "https://cdn.ipinfo.io/static/images/countries-flags/"
31
+
32
+
33
+ class << self
34
+ def create(access_token = nil, settings = {})
35
+ IPinfo.new(access_token, settings)
36
+ end
37
+ end
38
+ end
39
+
40
+ class IPinfo::IPinfo
41
+ include IPinfo
42
+ attr_accessor :access_token, :countries, :httpc
43
+
44
+ def initialize(access_token = nil, settings = {})
45
+ @access_token = access_token
46
+ @httpc = prepare_http_client(settings.fetch('http_client', nil))
47
+
48
+ maxsize = settings.fetch('maxsize', DEFAULT_CACHE_MAXSIZE)
49
+ ttl = settings.fetch('ttl', DEFAULT_CACHE_TTL)
50
+ @cache = settings.fetch('cache', DefaultCache.new(ttl, maxsize))
51
+ @countries = prepare_json(settings.fetch('countries',
52
+ DEFAULT_COUNTRY_FILE))
53
+ @eu_countries = prepare_json(settings.fetch('eu_countries',
54
+ DEFAULT_EU_COUNTRIES_FILE))
55
+ @countries_flags = prepare_json(settings.fetch('countries_flags',
56
+ DEFAULT_COUNTRIES_FLAG_FILE))
57
+ @countries_currencies = prepare_json(settings.fetch('countries_currencies',
58
+ DEFAULT_COUNTRIES_CURRENCIES_FILE))
59
+ @continents = prepare_json(settings.fetch('continents',
60
+ DEFAULT_CONTINENT_FILE))
21
61
  end
22
- end
23
62
 
24
- class IPinfo
25
- attr_accessor :access_token
26
- attr_accessor :countries
27
- attr_accessor :http_client
63
+ def details(ip_address = nil)
64
+ details = request_details(ip_address)
65
+ if details.key? :country
66
+ details[:country_name] =
67
+ @countries.fetch(details.fetch(:country), nil)
68
+ details[:is_eu] =
69
+ @eu_countries.include?(details.fetch(:country))
70
+ details[:country_flag] =
71
+ @countries_flags.fetch(details.fetch(:country), nil)
72
+ details[:country_currency] =
73
+ @countries_currencies.fetch(details.fetch(:country), nil)
74
+ details[:continent] =
75
+ @continents.fetch(details.fetch(:country), nil)
76
+ details[:country_flag_url] = COUNTRY_FLAGS_URL + details.fetch(:country) + ".svg"
77
+ end
78
+
79
+ if details.key? :ip
80
+ details[:ip_address] =
81
+ IPAddr.new(details.fetch(:ip))
82
+ end
83
+
84
+ if details.key? :loc
85
+ loc = details.fetch(:loc).split(',')
86
+ details[:latitude] = loc[0]
87
+ details[:longitude] = loc[1]
88
+ end
89
+
90
+ Response.new(details)
91
+ end
92
+
93
+ def get_map_url(ips)
94
+ if !ips.kind_of?(Array)
95
+ return JSON.generate({:error => 'Invalid input. Array required!'})
96
+ end
97
+ if ips.length > 500000
98
+ return JSON.generate({:error => 'No more than 500,000 ips allowed!'})
99
+ end
28
100
 
29
- def initialize(access_token=nil, settings={})
30
- @access_token = access_token
31
- @http_client = http_client(settings.fetch("http_client", nil))
101
+ json_ips = JSON.generate({:ips => ips})
102
+ res = @httpc.post('/tools/map', json_ips)
32
103
 
33
- maxsize = settings.fetch("maxsize", DEFAULT_CACHE_MAXSIZE)
34
- ttl = settings.fetch("ttl", DEFAULT_CACHE_TTL)
35
- @cache = settings.fetch("cache", DefaultCache.new(ttl, maxsize))
36
- @countries = countries(settings.fetch('countries', DEFAULT_COUNTRY_FILE))
104
+ obj = JSON.parse(res.body)
105
+ obj['reportUrl']
37
106
  end
38
107
 
39
- def details(ip_address=nil)
40
- details = request_details(ip_address)
41
- if details.has_key? :country
42
- details[:country_name] = @countries.fetch(details.fetch(:country), nil)
43
- end
108
+ def batch_requests(url_array, api_token)
109
+ result = Hash.new
110
+ lookup_ips = []
111
+
112
+ url_array.each { |url|
113
+ ip = @cache.get(cache_key(url))
114
+
115
+ unless ip.nil?
116
+ result.store(url, ip)
117
+ else
118
+ lookup_ips << url
119
+ end
120
+ }
121
+
122
+ if lookup_ips.empty?
123
+ return result
124
+ end
125
+
126
+ begin
127
+ lookup_ips.each_slice(1000){ |ips|
128
+ json_arr = JSON.generate(lookup_ips)
129
+ res = @httpc.post("/batch?token=#{api_token}", json_arr, 5)
130
+
131
+ raise StandardError, "Request Quota Exceeded" if res.status == 429
132
+
133
+ data = JSON.parse(res.body)
134
+ data.each { |key, val|
135
+ @cache.set(cache_key(key), val)
136
+ }
44
137
 
45
- if details.has_key? :ip
46
- details[:ip_address] = IPAddr.new(details.fetch(:ip))
47
- end
138
+ result.merge!(data)
139
+ }
48
140
 
49
- if details.has_key? :loc
50
- loc = details.fetch(:loc).split(",")
51
- details[:latitude] = loc[0]
52
- details[:longitude] = loc[1]
53
- end
141
+ rescue StandardError => e
142
+ return e.message
143
+ end
54
144
 
55
- Response.new(details)
145
+ result
56
146
  end
57
147
 
58
148
  protected
59
- def request_details(ip_address=nil)
60
- if !@cache.contains?(ip_address)
61
- response = @http_client.get(escape_path(ip_address))
62
149
 
63
- raise RateLimitError.new(RATE_LIMIT_MESSAGE) if response.status.eql?(429)
150
+ def request_details(ip_address = nil)
151
+ if isBogon(ip_address)
152
+ details[:ip] = ip_address
153
+ details[:bogon] = true
154
+ details[:ip_address] = IPAddr.new(ip_address)
155
+
156
+ return details
157
+ end
158
+
159
+ res = @cache.get(cache_key(ip_address))
160
+ return res unless res.nil?
161
+
162
+ response = @httpc.get(escape_path(ip_address))
163
+
164
+ if response.status.eql?(429)
165
+ raise RateLimitError,
166
+ RATE_LIMIT_MESSAGE
167
+ end
64
168
 
65
169
  details = JSON.parse(response.body, symbolize_names: true)
66
- @cache.set(ip_address, details)
67
- end
68
- @cache.get(ip_address)
170
+ @cache.set(cache_key(ip_address), details)
171
+ details
69
172
  end
70
173
 
71
- def http_client(http_client=nil)
72
- if http_client
73
- @http_client = Adapter.new(access_token, http_client)
74
- else
75
- @http_client = Adapter.new(access_token)
76
- end
174
+ def prepare_http_client(httpc = nil)
175
+ @httpc = if httpc
176
+ Adapter.new(access_token, httpc)
177
+ else
178
+ Adapter.new(access_token)
179
+ end
77
180
  end
78
181
 
79
- def countries(filename)
80
- file = File.read(filename)
81
- JSON.parse(file)
182
+ def prepare_json(filename)
183
+ file = File.read(filename)
184
+ JSON.parse(file)
82
185
  end
83
186
 
84
187
  private
188
+
189
+ def isBogon(ip)
190
+ if ip.nil?
191
+ return false
192
+ end
193
+
194
+ matcher_object = IpAddressMatcher.new(ip)
195
+ matcher_object.matches
196
+ end
197
+
85
198
  def escape_path(ip)
86
- ip ? "/#{CGI::escape(ip)}" : '/'
199
+ ip ? "/#{CGI.escape(ip)}" : '/'
200
+ end
201
+
202
+ def cache_key(ip)
203
+ "1:#{ip}"
87
204
  end
88
- end
89
205
  end