[ Ondřej Nový ]
[ Debian Janitor ]
New upstream release.
Debian Janitor
2 years ago
0 | name: (CI) | |
1 | ||
2 | on: | |
3 | push: | |
4 | branches: | |
5 | - ci | |
6 | ||
7 | jobs: | |
8 | build: | |
9 | name: Python ${{ matrix.python-version }}, django ${{ matrix.django-version }} | |
10 | runs-on: ubuntu-latest | |
11 | strategy: | |
12 | matrix: | |
13 | python-version: [3.6, 3.7, 3.8, pypy3] | |
14 | django-version: [2.2, 3.0, 3.1, 3.2] | |
15 | ||
16 | steps: | |
17 | - uses: actions/checkout@v2 | |
18 | - name: setup python | |
19 | uses: actions/setup-python@v2 | |
20 | with: | |
21 | python-version: ${{ matrix.python-version }} | |
22 | - name: Install dependencies | |
23 | run: | | |
24 | python -m pip install --upgrade pip | |
25 | pip install -e . | |
26 | pip install coveralls | |
27 | pip install "django~=${{ matrix.django-version }}.0" | |
28 | - name: Run flake8 | |
29 | run: | | |
30 | pip install flake8 | |
31 | flake8 --exclude=migrations,tests --ignore=E501,E241,E225,E128 . | |
32 | - name: Run pycodestyle | |
33 | run: | | |
34 | pip install pycodestyle | |
35 | pycodestyle --exclude=migrations,tests --ignore=E501,E241,E225,E128 . | |
36 | - name: Run test | |
37 | run: | | |
38 | coverage run --source=ipware manage.py test | |
39 | - name: Coveralls | |
40 | run: coveralls --service=github | |
41 | env: | |
42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
0 | name: DEV | |
1 | ||
2 | # Run on push only for dev/sandbox | |
3 | # Otherwise it may trigger concurrently `push & pull_request` on PRs. | |
4 | on: | |
5 | push: | |
6 | branches: | |
7 | - sandbox | |
8 | - dev | |
9 | ||
10 | jobs: | |
11 | build: | |
12 | name: Python ${{ matrix.python-version }}, django ${{ matrix.django-version }} | |
13 | runs-on: ubuntu-latest | |
14 | strategy: | |
15 | matrix: | |
16 | python-version: [3.6, 3.7, 3.8, pypy3] | |
17 | django-version: [2.2, 3.0, 3.1, 3.2] | |
18 | ||
19 | steps: | |
20 | - uses: actions/checkout@v2 | |
21 | - name: setup python | |
22 | uses: actions/setup-python@v2 | |
23 | with: | |
24 | python-version: ${{ matrix.python-version }} | |
25 | - name: Install dependencies | |
26 | run: | | |
27 | python -m pip install --upgrade pip | |
28 | pip install -e . | |
29 | pip install coveralls | |
30 | pip install "django~=${{ matrix.django-version }}.0" | |
31 | - name: Run flake8 | |
32 | run: | | |
33 | pip install flake8 | |
34 | flake8 --exclude=migrations,tests --ignore=E501,E241,E225,E128 . | |
35 | - name: Run pycodestyle | |
36 | run: | | |
37 | pip install pycodestyle | |
38 | pycodestyle --exclude=migrations,tests --ignore=E501,E241,E225,E128 . | |
39 | - name: Run test | |
40 | run: | | |
41 | coverage run --source=ipware manage.py test | |
42 | - name: Coveralls | |
43 | run: coveralls --service=github | |
44 | env: | |
45 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
0 | name: MAIN | |
1 | ||
2 | # Run on push only for main | |
3 | # Otherwise it may trigger concurrently `push & pull_request` on PRs. | |
4 | on: | |
5 | push: | |
6 | branches: | |
7 | - master | |
8 | ||
9 | ||
10 | jobs: | |
11 | build: | |
12 | name: Python ${{ matrix.python-version }}, django ${{ matrix.django-version }} | |
13 | runs-on: ubuntu-latest | |
14 | strategy: | |
15 | matrix: | |
16 | python-version: [3.6, 3.7, 3.8, pypy3] | |
17 | django-version: [2.2, 3.0, 3.1, 3.2] | |
18 | ||
19 | steps: | |
20 | - uses: actions/checkout@v2 | |
21 | - name: setup python | |
22 | uses: actions/setup-python@v2 | |
23 | with: | |
24 | python-version: ${{ matrix.python-version }} | |
25 | - name: Install dependencies | |
26 | run: | | |
27 | python -m pip install --upgrade pip | |
28 | pip install -e . | |
29 | pip install coveralls | |
30 | pip install "django~=${{ matrix.django-version }}.0" | |
31 | - name: Run flake8 | |
32 | run: | | |
33 | pip install flake8 | |
34 | flake8 --exclude=migrations,tests --ignore=E501,E241,E225,E128 . | |
35 | - name: Run pycodestyle | |
36 | run: | | |
37 | pip install pycodestyle | |
38 | pycodestyle --exclude=migrations,tests --ignore=E501,E241,E225,E128 . | |
39 | - name: Run test | |
40 | run: | | |
41 | coverage run --source=ipware manage.py test | |
42 | - name: Coveralls | |
43 | run: coveralls --service=github | |
44 | env: | |
45 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
0 | sudo: false | |
1 | language: python | |
2 | ||
3 | python: | |
4 | - "3.8" | |
5 | - "3.7" | |
6 | - "3.6" | |
7 | - "3.5" | |
8 | - "pypy3" | |
9 | ||
10 | env: | |
11 | - DJANGO="django==3.0.7" | |
12 | - DJANGO="django==2.2.8" | |
13 | ||
14 | install: | |
15 | - pip install $DJANGO | |
16 | - pip install -e . | |
17 | - pip install pycodestyle | |
18 | - pip install flake8 | |
19 | - pip install coveralls | |
20 | ||
21 | before_script: | |
22 | - "pycodestyle --exclude=migrations,tests --ignore=E501,E241,E225,E128 ." | |
23 | - "flake8 --exclude=migrations,tests --ignore=E501,E241,E225,E128 ." | |
24 | ||
25 | matrix: | |
26 | exclude: | |
27 | - python: "3.5" | |
28 | env: DJANGO="django==3.0.7" | |
29 | ||
30 | script: coverage run --source=ipware manage.py test | |
31 | ||
32 | after_success: | |
33 | coveralls | |
34 |
0 | 0 | { |
1 | "python.linting.enabled": false | |
2 | }⏎ | |
1 | "python.linting.enabled": false, | |
2 | "cSpell.words": [ | |
3 | "Neekman", | |
4 | "Neekware", | |
5 | "Pware", | |
6 | "cmdclass", | |
7 | "getattr", | |
8 | "ipware", | |
9 | "multicast", | |
10 | "noqa", | |
11 | "pycodestyle", | |
12 | "pyflakes", | |
13 | "routable", | |
14 | "setuptools", | |
15 | "stackoverflow", | |
16 | "vneekman" | |
17 | ] | |
18 | } |
0 | ## 3.0.4 / 3.0.5 / 3.0.6 / 3.0.7 | |
1 | ||
2 | Enhancement: | |
3 | ||
4 | - Clean ups | |
5 | ||
6 | ## 3.0.3 | |
7 | ||
8 | Enhancement: | |
9 | ||
10 | - Add support for github action (@awais786) | |
11 | ||
12 | ## 3.0.2 | |
13 | ||
14 | Enhancement: | |
15 | ||
16 | - Add support for ppc64le (@kishorkunal-raj) | |
17 | ||
18 | ## 3.0.1 | |
19 | ||
20 | Fix: | |
21 | ||
22 | - Ensure no-required build artifacts won't get into the package | |
23 | ||
0 | 24 | ## 3.0.0 |
1 | 25 | |
2 | 26 | Enhancement: |
3 | - Remove deprecated logic | |
4 | - Drop "official" support for py < 3.5 | |
5 | - Update to latest Django | |
6 | ||
27 | ||
28 | - Remove deprecated logic | |
29 | - Drop "official" support for py < 3.5 | |
30 | - Update to latest Django | |
31 | ||
7 | 32 | ## 2.1.1 |
8 | 33 | |
9 | 34 | Enhancement: |
10 | - Added deprecation warnings preparing for version 3.0 | |
11 | - Update to latest Django | |
12 | ||
35 | ||
36 | - Added deprecation warnings preparing for version 3.0 | |
37 | - Update to latest Django | |
38 | ||
13 | 39 | ## 2.1.0 |
14 | 40 | |
15 | 41 | Enhancement: |
16 | - Added more non-routable ip blocks (@wking) | |
42 | ||
43 | - Added more non-routable ip blocks (@wking) | |
17 | 44 | |
18 | 45 | ## 2.0.2 |
19 | 46 | |
20 | 47 | Enhancement: |
21 | - Added the ability to private the request precedence order on each call | |
48 | ||
49 | - Added the ability to private the request precedence order on each call | |
22 | 50 | |
23 | 51 | ## 2.0.1 |
24 | 52 | |
25 | 53 | Enhancement: |
26 | - Added more private IP blocks to the default list | |
54 | ||
55 | - Added more private IP blocks to the default list | |
27 | 56 | |
28 | 57 | ## 2.0.0 |
29 | 58 | |
30 | 59 | Fix: |
31 | - Update Django versions (@illagrenan) | |
32 | - Update Readme (@sabueso) | |
33 | - Added proxy count | |
34 | - Moved version one readme to /docs | |
60 | ||
61 | - Update Django versions (@illagrenan) | |
62 | - Update Readme (@sabueso) | |
63 | - Added proxy count | |
64 | - Moved version one readme to /docs | |
35 | 65 | |
36 | 66 | ## 1.1.6 |
37 | 67 | |
38 | 68 | Fix: |
39 | - Fix trusted proxies Right2Left + Test & Bumped Django versions (@felixxm) | |
40 | - Changed licensing to MIT | |
69 | ||
70 | - Fix trusted proxies Right2Left + Test & Bumped Django versions (@felixxm) | |
71 | - Changed licensing to MIT | |
41 | 72 | |
42 | 73 | ## 1.1.5 |
43 | 74 | |
44 | 75 | Feature: |
45 | - Added support for trusted proxy configuration | |
76 | ||
77 | - Added support for trusted proxy configuration | |
46 | 78 | |
47 | 79 | ## 1.1.4 |
48 | 80 | |
49 | 81 | Enhancement: |
50 | 82 | |
51 | - Added support for proxies with `underscores_in_headers off;` | |
52 | - Handling hyphen as delimiter - ex: `X-FORWARDED-FOR` instead of `X_FORWARDED_FOR` | |
53 | - Up version Django version in .travis.yml | |
54 | ||
83 | - Added support for proxies with `underscores_in_headers off;` | |
84 | - Handling hyphen as delimiter - ex: `X-FORWARDED-FOR` instead of `X_FORWARDED_FOR` | |
85 | - Up version Django version in .travis.yml | |
55 | 86 | |
56 | 87 | ## 1.1.3 |
57 | 88 | |
58 | 89 | Fix: |
59 | 90 | |
60 | - Fix read me file updating `IPWARE_META_PRECEDENCE_ORDER` reference. | |
61 | ||
91 | - Fix read me file updating `IPWARE_META_PRECEDENCE_ORDER` reference. | |
62 | 92 | |
63 | 93 | ## 1.1.2 |
64 | 94 | |
65 | 95 | Updates: |
66 | 96 | |
67 | - Added support for Django 1.8.6 and Python 3.5. | |
68 | - Dropped support for Django 1.4.x and Python 2.6 and 3.2 | |
69 | ||
97 | - Added support for Django 1.8.6 and Python 3.5. | |
98 | - Dropped support for Django 1.4.x and Python 2.6 and 3.2 | |
70 | 99 | |
71 | 100 | ## 1.1.1 |
72 | 101 | |
73 | 102 | Enhancement: |
74 | 103 | |
75 | - Added support for X_FORWARDED_FOR | |
76 | ||
104 | - Added support for X_FORWARDED_FOR | |
77 | 105 | |
78 | 106 | ## 1.1.0 |
79 | 107 | |
80 | 108 | Enhancement: |
81 | 109 | |
82 | - Added support for 1.0.0.0/8 and 2.0.0.0/8 blocks | |
83 | ||
110 | - Added support for 1.0.0.0/8 and 2.0.0.0/8 blocks | |
84 | 111 | |
85 | 112 | ## 1.0.0 |
86 | 113 | |
87 | 114 | Enhancement: |
88 | 115 | |
89 | - Promoting to production grade | |
90 | ||
116 | - Promoting to production grade | |
91 | 117 | |
92 | 118 | ## 0.1.1 |
93 | 119 | |
94 | 120 | Enhancement: |
95 | 121 | |
96 | - Support for Left2Right or Right2Left Proxy IP Lookup | |
97 | ||
122 | - Support for Left2Right or Right2Left Proxy IP Lookup | |
98 | 123 | |
99 | 124 | ## 0.1.0 |
100 | 125 | |
101 | 126 | Enhancement: |
102 | 127 | |
103 | - pypy support | |
104 | - PY3.4 support | |
105 | ||
128 | - pypy support | |
129 | - PY3.4 support | |
106 | 130 | |
107 | 131 | ## 0.0.9 |
108 | 132 | |
109 | 133 | Enhancement: |
110 | 134 | |
111 | - Django 1.7 official support | |
112 | - First non-loopback private IP match is best matched now. | |
113 | ||
135 | - Django 1.7 official support | |
136 | - First non-loopback private IP match is best matched now. | |
114 | 137 | |
115 | 138 | ## 0.0.8 |
116 | 139 | |
117 | 140 | Enhancement: |
118 | 141 | |
119 | - Django 1.7 support | |
120 | - PEP8 Compliance | |
121 | - Bump Alpha to Beta | |
122 | ||
142 | - Django 1.7 support | |
143 | - PEP8 Compliance | |
144 | - Bump Alpha to Beta | |
123 | 145 | |
124 | 146 | ## 0.0.6 |
125 | 147 | |
126 | 148 | Enhancement: |
127 | 149 | |
128 | - Converted print statements to new format. (Python 3.x) | |
129 | - Replaced deprecated unit test APIs | |
130 | ||
150 | - Converted print statements to new format. (Python 3.x) | |
151 | - Replaced deprecated unit test APIs | |
131 | 152 | |
132 | 153 | ## 0.0.5 |
133 | 154 | |
134 | 155 | Enhancement: |
135 | 156 | |
136 | - Added Python 3.2 and 3.3 support | |
137 | ||
157 | - Added Python 3.2 and 3.3 support | |
138 | 158 | |
139 | 159 | ## 0.0.4 |
140 | 160 | |
141 | 161 | Enhancement: |
142 | 162 | |
143 | - Added changelog file | |
144 | - Added more private ip prefixes | |
145 | ||
163 | - Added changelog file | |
164 | - Added more private ip prefixes | |
146 | 165 | |
147 | 166 | ## 0.0.3 |
148 | 167 | |
149 | 168 | Features: |
150 | 169 | |
151 | - Added get_ip() to return the best-matched IP | |
152 | - Removed get_ip_address_from_request() | |
170 | - Added get_ip() to return the best-matched IP | |
171 | - Removed get_ip_address_from_request() | |
153 | 172 | |
154 | 173 | Bugfixes: |
155 | 174 | |
156 | - Expended the private IP range | |
157 | ||
175 | - Expended the private IP range | |
158 | 176 | |
159 | 177 | ## 0.0.2 |
160 | 178 | |
161 | 179 | Features: |
162 | 180 | |
163 | - IPv6 support | |
164 | - Added get_real_ip(), the shorter version of get_ip_address_from_request() | |
165 | ||
181 | - IPv6 support | |
182 | - Added get_real_ip(), the shorter version of get_ip_address_from_request() | |
166 | 183 | |
167 | 184 | ## 0.0.1 |
168 | 185 | |
169 | 186 | Features: |
170 | 187 | |
171 | - Initial Release | |
188 | - Initial Release |
0 | Django IPware | |
1 | ==================== | |
0 | # Django IPware | |
2 | 1 | |
3 | 2 | **A Django application to retrieve client's IP address** |
4 | 3 | |
6 | 5 | [![version-image]][version-link] |
7 | 6 | [![coverage-image]][coverage-link] |
8 | 7 | |
9 | Overview | |
10 | ==================== | |
8 | # Overview | |
11 | 9 | |
12 | 10 | **Best attempt** to get client's IP address while keeping it **DRY**. |
13 | 11 | |
14 | Notice | |
15 | ==================== | |
16 | ||
17 | There is not a good *out-of-the-box* solution against fake IP addresses, aka *IP Address Spoofing*. | |
12 | # Notice | |
13 | ||
14 | There is not a good _out-of-the-box_ solution against fake IP addresses, aka _IP Address Spoofing_. | |
18 | 15 | You are encouraged to read the ([Advanced users](README.md#advanced-users)) section of this page and |
19 | use `trusted_proxies_ips` and/or `proxy_count` features to match your needs, especially *if* you are | |
20 | planning to include `ipware` in any authentication, security or *anti-fraud* related architecture. | |
21 | ||
22 | ||
23 | How to install | |
24 | ==================== | |
16 | use `trusted_proxies_ips` and/or `proxy_count` features to match your needs, especially _if_ you are | |
17 | planning to include `ipware` in any authentication, security or _anti-fraud_ related architecture. | |
18 | ||
19 | # How to install | |
25 | 20 | |
26 | 21 | 1. easy_install django-ipware |
27 | 22 | 2. pip install django-ipware |
33 | 28 | b. cd into django-ipware-* directory |
34 | 29 | c. run python setup.py install |
35 | 30 | |
36 | ||
37 | How to use | |
38 | ==================== | |
39 | ||
40 | ```python | |
41 | # In a view or a middleware where the `request` object is available | |
42 | ||
43 | from ipware import get_client_ip | |
44 | client_ip, is_routable = get_client_ip(request) | |
45 | if client_ip is None: | |
46 | # Unable to get the client's IP address | |
47 | else: | |
48 | # We got the client's IP address | |
49 | if is_routable: | |
50 | # The client's IP address is publicly routable on the Internet | |
51 | else: | |
52 | # The client's IP address is private | |
53 | ||
54 | # Order of precedence is (Public, Private, Loopback, None) | |
55 | ``` | |
56 | ||
57 | ||
58 | Advanced users: | |
59 | ==================== | |
31 | # How to use | |
32 | ||
33 | ```python | |
34 | # In a view or a middleware where the `request` object is available | |
35 | ||
36 | from ipware import get_client_ip | |
37 | client_ip, is_routable = get_client_ip(request) | |
38 | if client_ip is None: | |
39 | # Unable to get the client's IP address | |
40 | else: | |
41 | # We got the client's IP address | |
42 | if is_routable: | |
43 | # The client's IP address is publicly routable on the Internet | |
44 | else: | |
45 | # The client's IP address is private | |
46 | ||
47 | # Order of precedence is (Public, Private, Loopback, None) | |
48 | ``` | |
49 | ||
50 | # Advanced users: | |
60 | 51 | |
61 | 52 | - ### Precedence Order |
62 | The default meta precedence order is top to bottom. However, you may customize the order | |
63 | by providing your own `IPWARE_META_PRECEDENCE_ORDER` by adding it to your project's settings.py | |
64 | ||
65 | ```python | |
66 | # The default meta precedence order | |
67 | IPWARE_META_PRECEDENCE_ORDER = ( | |
68 | 'HTTP_X_FORWARDED_FOR', 'X_FORWARDED_FOR', # <client>, <proxy1>, <proxy2> | |
69 | 'HTTP_CLIENT_IP', | |
70 | 'HTTP_X_REAL_IP', | |
71 | 'HTTP_X_FORWARDED', | |
72 | 'HTTP_X_CLUSTER_CLIENT_IP', | |
73 | 'HTTP_FORWARDED_FOR', | |
74 | 'HTTP_FORWARDED', | |
75 | 'HTTP_VIA', | |
76 | 'REMOTE_ADDR', | |
77 | ) | |
78 | ``` | |
79 | **Alternatively**, you can provide your custom *request header meta precedence order* when calling `get_client_ip()`. | |
53 | ||
54 | The default meta precedence order is top to bottom. However, you may customize the order | |
55 | by providing your own `IPWARE_META_PRECEDENCE_ORDER` by adding it to your project's settings.py | |
56 | ||
57 | ```python | |
58 | # The default meta precedence order | |
59 | IPWARE_META_PRECEDENCE_ORDER = ( | |
60 | 'HTTP_X_FORWARDED_FOR', 'X_FORWARDED_FOR', # <client>, <proxy1>, <proxy2> | |
61 | 'HTTP_CLIENT_IP', | |
62 | 'HTTP_X_REAL_IP', | |
63 | 'HTTP_X_FORWARDED', | |
64 | 'HTTP_X_CLUSTER_CLIENT_IP', | |
65 | 'HTTP_FORWARDED_FOR', | |
66 | 'HTTP_FORWARDED', | |
67 | 'HTTP_VIA', | |
68 | 'REMOTE_ADDR', | |
69 | ) | |
70 | ``` | |
71 | ||
72 | **Alternatively**, you can provide your custom _request header meta precedence order_ when calling `get_client_ip()`. | |
73 | ||
80 | 74 | ```python |
81 | 75 | get_client_ip(request, request_header_order=['X_FORWARDED_FOR']) |
82 | 76 | get_client_ip(request, request_header_order=['X_FORWARDED_FOR', 'HTTP_X_FORWARDED_FOR']) |
85 | 79 | ### Private Prefixes |
86 | 80 | |
87 | 81 | You may customize the prefixes to indicate an IP address is private. This is done by adding your |
88 | own `IPWARE_PRIVATE_IP_PREFIX` to your project's settings.py. IP addresses matching the following | |
89 | prefixes are considered *private* & are **not** publicly routable. | |
90 | ||
91 | ```python | |
92 | # The default private IP prefixes | |
93 | IPWARE_PRIVATE_IP_PREFIX = getattr(settings, | |
94 | 'IPWARE_PRIVATE_IP_PREFIX', ( | |
95 | '0.', # messages to software | |
96 | '10.', # class A private block | |
97 | '100.64.', '100.65.', '100.66.', '100.67.', '100.68.', '100.69.', | |
98 | '100.70.', '100.71.', '100.72.', '100.73.', '100.74.', '100.75.', | |
99 | '100.76.', '100.77.', '100.78.', '100.79.', '100.80.', '100.81.', | |
100 | '100.82.', '100.83.', '100.84.', '100.85.', '100.86.', '100.87.', | |
101 | '100.88.', '100.89.', '100.90.', '100.91.', '100.92.', '100.93.', | |
102 | '100.94.', '100.95.', '100.96.', '100.97.', '100.98.', '100.99.', | |
103 | '100.100.', '100.101.', '100.102.', '100.103.', '100.104.', '100.105.', | |
104 | '100.106.', '100.107.', '100.108.', '100.109.', '100.110.', '100.111.', | |
105 | '100.112.', '100.113.', '100.114.', '100.115.', '100.116.', '100.117.', | |
106 | '100.118.', '100.119.', '100.120.', '100.121.', '100.122.', '100.123.', | |
107 | '100.124.', '100.125.', '100.126.', '100.127.', # carrier-grade NAT | |
108 | '169.254.', # link-local block | |
109 | '172.16.', '172.17.', '172.18.', '172.19.', | |
110 | '172.20.', '172.21.', '172.22.', '172.23.', | |
111 | '172.24.', '172.25.', '172.26.', '172.27.', | |
112 | '172.28.', '172.29.', '172.30.', '172.31.', # class B private blocks | |
113 | '192.0.0.', # reserved for IANA special purpose address registry | |
114 | '192.0.2.', # reserved for documentation and example code | |
115 | '192.168.', # class C private block | |
116 | '198.18.', '198.19.', # reserved for inter-network communications between two separate subnets | |
117 | '198.51.100.', # reserved for documentation and example code | |
118 | '203.0.113.', # reserved for documentation and example code | |
119 | '224.', '225.', '226.', '227.', '228.', '229.', '230.', '231.', '232.', | |
120 | '233.', '234.', '235.', '236.', '237.', '238.', '239.', # multicast | |
121 | '240.', '241.', '242.', '243.', '244.', '245.', '246.', '247.', '248.', | |
122 | '249.', '250.', '251.', '252.', '253.', '254.', '255.', # reserved | |
123 | ) + ( | |
124 | '::', # Unspecified address | |
125 | '::ffff:', '2001:10:', '2001:20:' # messages to software | |
126 | '2001::', # TEREDO | |
127 | '2001:2::', # benchmarking | |
128 | '2001:db8:', # reserved for documentation and example code | |
129 | 'fc00:', # IPv6 private block | |
130 | 'fe80:', # link-local unicast | |
131 | 'ff00:', # IPv6 multicast | |
132 | ) | |
133 | ) | |
134 | ``` | |
82 | own `IPWARE_PRIVATE_IP_PREFIX` to your project's settings.py. IP addresses matching the following | |
83 | prefixes are considered _private_ & are **not** publicly routable. | |
84 | ||
85 | ```python | |
86 | # The default private IP prefixes | |
87 | IPWARE_PRIVATE_IP_PREFIX = getattr(settings, | |
88 | 'IPWARE_PRIVATE_IP_PREFIX', ( | |
89 | '0.', # messages to software | |
90 | '10.', # class A private block | |
91 | '100.64.', '100.65.', '100.66.', '100.67.', '100.68.', '100.69.', | |
92 | '100.70.', '100.71.', '100.72.', '100.73.', '100.74.', '100.75.', | |
93 | '100.76.', '100.77.', '100.78.', '100.79.', '100.80.', '100.81.', | |
94 | '100.82.', '100.83.', '100.84.', '100.85.', '100.86.', '100.87.', | |
95 | '100.88.', '100.89.', '100.90.', '100.91.', '100.92.', '100.93.', | |
96 | '100.94.', '100.95.', '100.96.', '100.97.', '100.98.', '100.99.', | |
97 | '100.100.', '100.101.', '100.102.', '100.103.', '100.104.', '100.105.', | |
98 | '100.106.', '100.107.', '100.108.', '100.109.', '100.110.', '100.111.', | |
99 | '100.112.', '100.113.', '100.114.', '100.115.', '100.116.', '100.117.', | |
100 | '100.118.', '100.119.', '100.120.', '100.121.', '100.122.', '100.123.', | |
101 | '100.124.', '100.125.', '100.126.', '100.127.', # carrier-grade NAT | |
102 | '169.254.', # link-local block | |
103 | '172.16.', '172.17.', '172.18.', '172.19.', | |
104 | '172.20.', '172.21.', '172.22.', '172.23.', | |
105 | '172.24.', '172.25.', '172.26.', '172.27.', | |
106 | '172.28.', '172.29.', '172.30.', '172.31.', # class B private blocks | |
107 | '192.0.0.', # reserved for IANA special purpose address registry | |
108 | '192.0.2.', # reserved for documentation and example code | |
109 | '192.168.', # class C private block | |
110 | '198.18.', '198.19.', # reserved for inter-network communications between two separate subnets | |
111 | '198.51.100.', # reserved for documentation and example code | |
112 | '203.0.113.', # reserved for documentation and example code | |
113 | '224.', '225.', '226.', '227.', '228.', '229.', '230.', '231.', '232.', | |
114 | '233.', '234.', '235.', '236.', '237.', '238.', '239.', # multicast | |
115 | '240.', '241.', '242.', '243.', '244.', '245.', '246.', '247.', '248.', | |
116 | '249.', '250.', '251.', '252.', '253.', '254.', '255.', # reserved | |
117 | ) + ( | |
118 | '::', # Unspecified address | |
119 | '::ffff:', '2001:10:', '2001:20:' # messages to software | |
120 | '2001::', # TEREDO | |
121 | '2001:2::', # benchmarking | |
122 | '2001:db8:', # reserved for documentation and example code | |
123 | 'fc00:', # IPv6 private block | |
124 | 'fe80:', # link-local unicast | |
125 | 'ff00:', # IPv6 multicast | |
126 | ) | |
127 | ) | |
128 | ``` | |
135 | 129 | |
136 | 130 | ### Trusted Proxies |
137 | 131 | |
139 | 133 | by providing the `trusted` proxy list when calling `get_client_ip(request, proxy_trusted_ips=['177.139.233.133'])`. |
140 | 134 | In the following example, your load balancer (LB) can be seen as a `trusted` proxy. |
141 | 135 | |
142 | ``` | |
143 | `Real` Client <public> <---> <public> LB (Server) <private> <--------> <private> Django Server | |
144 | ^ | |
145 | | | |
146 | `Fake` Client <private> <---> <private> LB (Server) <private> ---^ | |
147 | ``` | |
148 | ||
149 | ||
150 | ```python | |
151 | # In the above scenario, use your load balancer's IP address as a way to filter out unwanted requests. | |
152 | client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.233.133']) | |
153 | ||
154 | # If you have multiple proxies, simply add them to the list | |
155 | client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.233.133', '177.139.233.134']) | |
156 | ||
157 | # For proxy servers with fixed sub-domain and dynamic IP, use the following pattern. | |
158 | client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.', '177.140']) | |
159 | client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.233.', '177.139.240']) | |
160 | ``` | |
136 | ``` | |
137 | `Real` Client <public> <---> <public> LB (Server) <private> <--------> <private> Django Server | |
138 | ^ | |
139 | | | |
140 | `Fake` Client <private> <---> <private> LB (Server) <private> ---^ | |
141 | ``` | |
142 | ||
143 | ```python | |
144 | # In the above scenario, use your load balancer IP address as a way to filter out unwanted requests. | |
145 | client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.233.133']) | |
146 | ||
147 | # If you have multiple proxies, simply add them to the list | |
148 | client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.233.133', '177.139.233.134']) | |
149 | ||
150 | # For proxy servers with fixed sub-domain and dynamic IP, use the following pattern. | |
151 | client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.', '177.140']) | |
152 | client_ip, is_routable = get_client_ip(request, proxy_trusted_ips=['177.139.233.', '177.139.240']) | |
153 | ``` | |
161 | 154 | |
162 | 155 | ### Proxy Count |
163 | 156 | |
164 | If your Django server is behind a *known* number of proxy server(s), you can filter out unwanted requests | |
165 | by providing the *number* of proxies when calling `get_client_ip(request, proxy_count=1)`. | |
166 | In the following example, your load balancer (LB) can be seen as the *only* proxy. | |
167 | ||
168 | ``` | |
169 | `Real` Client <public> <---> <public> LB (Server) <private> <--------> <private> Django Server | |
170 | ^ | |
171 | | | |
172 | `Fake` Client <private> ---^ | |
173 | ``` | |
174 | ||
175 | ```python | |
176 | # In the above scenario, the total number of proxies can be used as a way to filter out unwanted requests. | |
177 | client_ip, is_routable = get_client_ip(request, proxy_count=1) | |
178 | ||
179 | # The above may be very useful in cases where your proxy server's IP address is assigned dynamically. | |
180 | # However, If you have the proxy IP address, you can use it in combination to the proxy count. | |
181 | client_ip, is_routable = get_client_ip(request, proxy_count=1, proxy_trusted_ips=['177.139.233.133']) | |
182 | ``` | |
157 | If your Django server is behind a _known_ number of proxy server(s), you can filter out unwanted requests | |
158 | by providing the _number_ of proxies when calling `get_client_ip(request, proxy_count=1)`. | |
159 | In the following example, your load balancer (LB) can be seen as the _only_ proxy. | |
160 | ||
161 | ``` | |
162 | `Real` Client <public> <---> <public> LB (Server) <private> <--------> <private> Django Server | |
163 | ^ | |
164 | | | |
165 | `Fake` Client <private> ---^ | |
166 | ``` | |
167 | ||
168 | ```python | |
169 | # In the above scenario, the total number of proxies can be used as a way to filter out unwanted requests. | |
170 | client_ip, is_routable = get_client_ip(request, proxy_count=1) | |
171 | ||
172 | # The above may be very useful in cases where your proxy server's IP address is assigned dynamically. | |
173 | # However, If you have the proxy IP address, you can use it in combination to the proxy count. | |
174 | client_ip, is_routable = get_client_ip(request, proxy_count=1, proxy_trusted_ips=['177.139.233.133']) | |
175 | ``` | |
183 | 176 | |
184 | 177 | ### Originating Request |
185 | 178 | |
186 | 179 | If your proxy server is configured such that the right-most IP address is that of the originating client, you |
187 | 180 | can indicate `right-most` as your `proxy_order` when calling `get_client_ip(request, proxy_order="right-most")`. |
188 | 181 | Please note that the [de-facto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) standard |
189 | for the originating client IP address is the `left-most` as per `<client>, <proxy1>, <proxy2>`. | |
190 | ||
191 | Running the tests | |
192 | ==================== | |
182 | for the originating client IP address is the `left-most` as per `<client>, <proxy1>, <proxy2>`. | |
183 | ||
184 | # Running the tests | |
193 | 185 | |
194 | 186 | To run the tests against the current environment: |
195 | 187 | |
196 | 188 | python manage.py test |
197 | 189 | |
198 | ||
199 | License | |
200 | ==================== | |
190 | # License | |
201 | 191 | |
202 | 192 | Released under a ([MIT](LICENSE)) license. |
203 | 193 | |
204 | ||
205 | Version | |
206 | ==================== | |
194 | # Version | |
195 | ||
207 | 196 | X.Y.Z Version |
208 | 197 | |
209 | 198 | `MAJOR` version -- when you make incompatible API changes, |
212 | 201 | |
213 | 202 | [status-image]: https://travis-ci.org/un33k/django-ipware.svg?branch=master |
214 | 203 | [status-link]: https://travis-ci.org/un33k/django-ipware |
215 | ||
216 | 204 | [version-image]: https://img.shields.io/pypi/v/django-ipware.svg |
217 | 205 | [version-link]: https://pypi.python.org/pypi/django-ipware |
218 | ||
219 | 206 | [coverage-image]: https://coveralls.io/repos/un33k/django-ipware/badge.svg |
220 | 207 | [coverage-link]: https://coveralls.io/r/un33k/django-ipware |
221 | ||
222 | 208 | [download-image]: https://img.shields.io/pypi/dm/django-ipware.svg |
223 | 209 | [download-link]: https://pypi.python.org/pypi/django-ipware |
224 | 210 | |
225 | ||
226 | Sponsors | |
227 | ==================== | |
211 | # Sponsors | |
228 | 212 | |
229 | 213 | [Neekware Inc.](http://neekware.com) |
0 | django-ipware (3.0.0-2) UNRELEASED; urgency=medium | |
0 | django-ipware (3.0.7-1) UNRELEASED; urgency=medium | |
1 | 1 | |
2 | [ Ondřej Nový ] | |
2 | 3 | * d/control: Update Maintainer field with new Debian Python Team |
3 | 4 | contact address. |
4 | 5 | * d/control: Update Vcs-* fields with new Debian Python Team Salsa |
5 | 6 | layout. |
6 | 7 | |
7 | -- Ondřej Nový <onovy@debian.org> Thu, 24 Sep 2020 08:49:21 +0200 | |
8 | [ Debian Janitor ] | |
9 | * New upstream release. | |
10 | ||
11 | -- Ondřej Nový <onovy@debian.org> Thu, 19 Aug 2021 10:09:41 -0000 | |
8 | 12 | |
9 | 13 | django-ipware (3.0.0-1) unstable; urgency=low |
10 | 14 |
0 | ### Nginx Users | |
1 | ||
2 | By default,using Ningx as a reverse proxy to Gunicorn doesn't forward the client's IP to gunicorn. | |
3 | As a reverse proxy, NGINX will receive HTTP requests from clients and then send those requests to our | |
4 | Gunicorn WSGI server. The problem is that NGINX hides information from our WSGI server. | |
5 | The HTTP request that Gunicorn receives is not the same as the one that NGINX received from the client. | |
6 | To solve this problem, open up your `nginx conf file` and add the following lines to the `location` block | |
7 | ``` | |
8 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |
9 | proxy_set_header Host $host; | |
10 | proxy_set_header X-Forwarded-Proto $scheme; | |
11 | ``` | |
12 | ||
13 | ``` | |
14 | server { | |
15 | listen 80; | |
16 | location / { | |
17 | include proxy_params; | |
18 | proxy_pass http://unix:/<where_your_sock_file_is>/coincard.sock; | |
19 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |
20 | proxy_set_header Host $host; | |
21 | proxy_set_header X-Forwarded-Proto $scheme; | |
22 | } | |
23 | } | |
24 | ||
25 | ```⏎ |
0 | 0 | from .ip import get_client_ip # noqa |
1 | 1 | |
2 | 2 | default_app_config = 'ipware.apps.IPwareConfig' |
3 | ||
4 | __author__ = 'Val Neekman @ Neekware Inc. [@vneekman]' | |
5 | __description__ = "A Django application to retrieve user's IP address" | |
6 | __version__ = '3.0.0' |
0 | __title__ = 'django-ipware' | |
1 | __author__ = 'Val Neekman' | |
2 | __author_email__ = 'info@neekware.com' | |
3 | __description__ = "A Django application to retrieve user's IP address" | |
4 | __url__ = 'https://github.com/un33k/django-ipware' | |
5 | __license__ = 'MIT' | |
6 | __copyright__ = 'Copyright 2020 Val Neekman @ Neekware Inc.' | |
7 | __version__ = '3.0.7' |
0 | [build-system] | |
1 | requires = [ | |
2 | "setuptools>=42", | |
3 | "wheel" | |
4 | ] | |
5 | build-backend = "setuptools.build_meta" |
0 | Django==3.0.7 | |
1 | pycodestyle==2.6.0 | |
2 | flake8==3.8.3 | |
0 | Django==3.2.5 | |
1 | pycodestyle==2.7.0 | |
2 | flake8==3.9.2 | |
3 | twine==3.4.2 |
0 | 0 | #!/usr/bin/env python |
1 | # -*- coding: utf-8 -*- | |
2 | ||
3 | from setuptools import setup | |
4 | import re | |
1 | # Learn more: https://github.com/kennethreitz/setup.py | |
5 | 2 | import os |
6 | 3 | import sys |
7 | 4 | |
8 | ||
9 | name = 'django-ipware' | |
10 | package = 'ipware' | |
11 | description = "A Django utility application that returns client's real IP address" | |
12 | url = 'https://github.com/un33k/django-ipware' | |
13 | author = 'Val Neekman' | |
14 | author_email = 'info@neekware.com' | |
15 | license = 'MIT' | |
16 | install_requires = [''] | |
17 | classifiers = [ | |
18 | 'Development Status :: 5 - Production/Stable', | |
19 | 'Environment :: Web Environment', | |
20 | 'Intended Audience :: Developers', | |
21 | 'License :: OSI Approved :: MIT License', | |
22 | 'Operating System :: OS Independent', | |
23 | 'Programming Language :: Python', | |
24 | 'Programming Language :: Python :: 2.7', | |
25 | 'Programming Language :: Python :: 3.4', | |
26 | 'Programming Language :: Python :: 3.5', | |
27 | 'Programming Language :: Python :: 3.6', | |
28 | 'Topic :: Utilities' | |
29 | ] | |
5 | from codecs import open | |
6 | from shutil import rmtree | |
7 | from setuptools import setup | |
30 | 8 | |
31 | 9 | |
32 | def get_version(package): | |
33 | """ | |
34 | Return package version as listed in `__version__` in `init.py`. | |
35 | """ | |
36 | init_py = open(os.path.join(package, '__init__.py')).read() | |
37 | return re.search("^__version__ = ['\"]([^'\"]+)['\"]", init_py, re.MULTILINE).group(1) | |
10 | package = 'ipware' | |
11 | python_requires = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" | |
12 | here = os.path.abspath(os.path.dirname(__file__)) | |
13 | ||
14 | requires = [] | |
15 | test_requirements = [] | |
16 | ||
17 | about = {} | |
18 | with open(os.path.join(here, package, '__version__.py'), 'r', 'utf-8') as f: | |
19 | exec(f.read(), about) | |
20 | ||
21 | with open('README.md', 'r', 'utf-8') as f: | |
22 | readme = f.read() | |
38 | 23 | |
39 | 24 | |
40 | def get_packages(package): | |
41 | """ | |
42 | Return root package and all sub-packages. | |
43 | """ | |
44 | return [dirpath | |
45 | for dirpath, dirnames, filenames in os.walk(package) | |
46 | if os.path.exists(os.path.join(dirpath, '__init__.py'))] | |
25 | def status(s): | |
26 | print('\033[1m{0}\033[0m'.format(s)) | |
47 | 27 | |
48 | 28 | |
49 | def get_package_data(package): | |
50 | """ | |
51 | Return all files under the root package, that are not in a | |
52 | package themselves. | |
53 | """ | |
54 | walk = [(dirpath.replace(package + os.sep, '', 1), filenames) | |
55 | for dirpath, dirnames, filenames in os.walk(package) | |
56 | if not os.path.exists(os.path.join(dirpath, '__init__.py'))] | |
29 | # 'setup.py publish' shortcut. | |
30 | if sys.argv[-1] == 'publish': | |
31 | try: | |
32 | status('Removing previous builds…') | |
33 | rmtree(os.path.join(here, 'dist')) | |
34 | except OSError: | |
35 | pass | |
57 | 36 | |
58 | filepaths = [] | |
59 | for base, filenames in walk: | |
60 | filepaths.extend([os.path.join(base, filename) | |
61 | for filename in filenames]) | |
62 | return {package: filepaths} | |
37 | status('Building Source and Wheel (universal) distribution…') | |
38 | os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) | |
63 | 39 | |
40 | status('Uploading the package to PyPI via Twine…') | |
41 | os.system('twine upload dist/*') | |
64 | 42 | |
65 | if sys.argv[-1] == 'publish': | |
66 | os.system("python setup.py sdist upload") | |
67 | args = {'version': get_version(package)} | |
68 | print("You probably want to also tag the version now:") | |
69 | print(" git tag -a %(version)s -m 'version %(version)s' && git push --tags" % args) | |
43 | status('Pushing git tags…') | |
44 | os.system('git tag v{0}'.format(about['__version__'])) | |
45 | os.system('git push --tags') | |
70 | 46 | sys.exit() |
71 | 47 | |
72 | ||
73 | 48 | setup( |
74 | name=name, | |
75 | version=get_version(package), | |
76 | url=url, | |
77 | license=license, | |
78 | description=description, | |
79 | author=author, | |
80 | author_email=author_email, | |
81 | packages=get_packages(package), | |
82 | package_data=get_package_data(package), | |
83 | install_requires=install_requires, | |
84 | classifiers=classifiers | |
49 | name=about['__title__'], | |
50 | version=about['__version__'], | |
51 | description=about['__description__'], | |
52 | long_description=readme, | |
53 | long_description_content_type='text/markdown', | |
54 | author=about['__author__'], | |
55 | author_email=about['__author_email__'], | |
56 | url=about['__url__'], | |
57 | packages=[package], | |
58 | package_data={'': ['LICENSE']}, | |
59 | package_dir={'ipware': 'ipware'}, | |
60 | include_package_data=True, | |
61 | python_requires=python_requires, | |
62 | install_requires=requires, | |
63 | license=about['__license__'], | |
64 | zip_safe=False, | |
65 | classifiers=[ | |
66 | 'Development Status :: 5 - Production/Stable', | |
67 | 'Intended Audience :: Developers', | |
68 | 'Natural Language :: English', | |
69 | 'License :: OSI Approved :: Apache Software License', | |
70 | 'Programming Language :: Python', | |
71 | 'Programming Language :: Python :: 3', | |
72 | 'Programming Language :: Python :: 3.6', | |
73 | 'Programming Language :: Python :: 3.7', | |
74 | 'Programming Language :: Python :: 3.8', | |
75 | 'Programming Language :: Python :: 3.9', | |
76 | ], | |
77 | cmdclass={}, | |
78 | tests_require=test_requirements, | |
79 | extras_require={}, | |
80 | project_urls={}, | |
85 | 81 | ) |