IPinfo 0.1.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.editorconfig +1 -1
- data/.github/workflows/cd_rubygems.yaml +34 -0
- data/.github/workflows/unittest.yaml +31 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +48 -0
- data/.ruby-version +1 -0
- data/Gemfile +7 -28
- data/README.md +126 -24
- data/Rakefile +8 -6
- data/bin/console +4 -10
- data/bin/setup +1 -2
- data/ipinfo.gemspec +21 -29
- data/lib/ipinfo/adapter.rb +23 -18
- data/lib/ipinfo/cache/cache_interface.rb +10 -9
- data/lib/ipinfo/cache/default_cache.rb +8 -9
- data/lib/ipinfo/continent.json +252 -0
- data/lib/ipinfo/currency.json +253 -0
- data/lib/ipinfo/errors.rb +3 -3
- data/lib/ipinfo/eu.json +1 -0
- data/lib/ipinfo/flags.json +252 -0
- data/lib/ipinfo/ipAddressMatcher.rb +92 -0
- data/lib/ipinfo/mod.rb +4 -0
- data/lib/ipinfo/response.rb +8 -9
- data/lib/ipinfo/version.rb +3 -1
- data/lib/ipinfo.rb +168 -52
- metadata +27 -24
- data/.travis.yml +0 -13
@@ -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
data/lib/ipinfo/response.rb
CHANGED
@@ -3,18 +3,17 @@
|
|
3
3
|
require 'ipaddr'
|
4
4
|
require 'json'
|
5
5
|
|
6
|
-
|
7
|
-
class Response
|
8
|
-
|
6
|
+
class IPinfo::Response
|
9
7
|
attr_reader :all
|
10
8
|
|
11
9
|
def initialize(response)
|
12
|
-
|
10
|
+
@all = response
|
11
|
+
|
12
|
+
@all.each do |name, value|
|
13
|
+
instance_variable_set("@#{name}", value)
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
15
|
+
c = class << self; self end
|
16
|
+
c.send(:attr_accessor, name)
|
17
|
+
end
|
18
18
|
end
|
19
|
-
end
|
20
19
|
end
|
data/lib/ipinfo/version.rb
CHANGED
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
30
|
-
|
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
|
-
|
34
|
-
|
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
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
|
46
|
-
|
47
|
-
end
|
138
|
+
result.merge!(data)
|
139
|
+
}
|
48
140
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
details[:longitude] = loc[1]
|
53
|
-
end
|
141
|
+
rescue StandardError => e
|
142
|
+
return e.message
|
143
|
+
end
|
54
144
|
|
55
|
-
|
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
|
-
|
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
|
-
|
68
|
-
@cache.get(ip_address)
|
170
|
+
@cache.set(cache_key(ip_address), details)
|
171
|
+
details
|
69
172
|
end
|
70
173
|
|
71
|
-
def
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
80
|
-
|
81
|
-
|
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
|
-
|
199
|
+
ip ? "/#{CGI.escape(ip)}" : '/'
|
200
|
+
end
|
201
|
+
|
202
|
+
def cache_key(ip)
|
203
|
+
"1:#{ip}"
|
87
204
|
end
|
88
|
-
end
|
89
205
|
end
|