├── app
├── static
│ ├── js
│ │ └── letmein.js
│ └── images
│ │ └── locks
│ │ ├── ABUS_E50.png
│ │ ├── ABUS_E60.png
│ │ ├── BRICARD_alpha.png
│ │ ├── THIRARD_unknown_1.png
│ │ ├── MASTER_security_20mm.png
│ │ ├── MASTER_security_40mm.png
│ │ ├── YELLOW_LINE_unknown_1.png
│ │ └── YELLOW_LINE_unknown_2.png
├── __init__.py
├── main.py
├── templates
│ ├── base.html
│ └── index.html
└── locks.json
├── runtime.txt
├── Procfile
├── images
└── screen.png
├── requirements.txt
└── readme.md
/app/static/js/letmein.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.10.4
2 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn "app:create_app()"
2 |
--------------------------------------------------------------------------------
/images/screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shellchocolat/ShareLocks/HEAD/images/screen.png
--------------------------------------------------------------------------------
/app/static/images/locks/ABUS_E50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shellchocolat/ShareLocks/HEAD/app/static/images/locks/ABUS_E50.png
--------------------------------------------------------------------------------
/app/static/images/locks/ABUS_E60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shellchocolat/ShareLocks/HEAD/app/static/images/locks/ABUS_E60.png
--------------------------------------------------------------------------------
/app/static/images/locks/BRICARD_alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shellchocolat/ShareLocks/HEAD/app/static/images/locks/BRICARD_alpha.png
--------------------------------------------------------------------------------
/app/static/images/locks/THIRARD_unknown_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shellchocolat/ShareLocks/HEAD/app/static/images/locks/THIRARD_unknown_1.png
--------------------------------------------------------------------------------
/app/static/images/locks/MASTER_security_20mm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shellchocolat/ShareLocks/HEAD/app/static/images/locks/MASTER_security_20mm.png
--------------------------------------------------------------------------------
/app/static/images/locks/MASTER_security_40mm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shellchocolat/ShareLocks/HEAD/app/static/images/locks/MASTER_security_40mm.png
--------------------------------------------------------------------------------
/app/static/images/locks/YELLOW_LINE_unknown_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shellchocolat/ShareLocks/HEAD/app/static/images/locks/YELLOW_LINE_unknown_1.png
--------------------------------------------------------------------------------
/app/static/images/locks/YELLOW_LINE_unknown_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shellchocolat/ShareLocks/HEAD/app/static/images/locks/YELLOW_LINE_unknown_2.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Jinja2==2.11.2
2 | flask==1.1.2
3 | flask_cors==3.0.10
4 | gunicorn==20.1.0
5 | markupsafe==2.0.1
6 | itsdangerous==1.1.0
7 | werkzeug==2.0.3
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | Start the application:
2 | ```
3 | $ gunicorn --bind 0.0.0.0:5000 "app:create_app()"
4 | ```
5 |
6 | If you lockpick a lock with success and want other people to do the same as you, you could fill the __locks.json__ file.
7 |
8 | The application will display some tips about the lock:
9 |
10 | * How many pins?
11 |
12 | * How many security pins? and position, and shape
13 |
14 | * Which method to use to unlock?
15 |
16 | * The difficulty
17 |
18 | * Some tips
19 |
20 |
21 | 
22 |
--------------------------------------------------------------------------------
/app/__init__.py:
--------------------------------------------------------------------------------
1 | # __init__.py
2 |
3 | from flask import Flask
4 | from flask_cors import CORS, cross_origin
5 | import json
6 | import os
7 |
8 | current_dir = os.getcwd()
9 | with open("./app/locks.json", "r") as fp:
10 | locks = fp.read()
11 | locks = json.loads(locks)
12 |
13 | def create_app():
14 | app = Flask(__name__,
15 | static_url_path='/static',
16 | static_folder='static',
17 | template_folder='templates')
18 |
19 | cors = CORS(app)
20 | app.config['CORS_HEADERS'] = 'Content-Type'
21 |
22 | from .main import main as main_blueprint
23 | app.register_blueprint(main_blueprint)
24 |
25 | return app
26 |
27 |
--------------------------------------------------------------------------------
/app/main.py:
--------------------------------------------------------------------------------
1 | # main.py
2 |
3 | from flask import Blueprint, render_template, request, send_from_directory
4 | from flask_cors import CORS, cross_origin
5 | from . import locks
6 |
7 | main = Blueprint('main', __name__)
8 |
9 | @main.route('/', methods=['GET'])
10 | @cross_origin()
11 | def home():
12 | brands = list_brands()
13 | num_locks = get_num_locks()
14 | return render_template('index.html', brands=brands, num_locks=num_locks)
15 |
16 | def list_brands():
17 | brands = {}
18 | for brand in locks["locks"]:
19 | brands[brand] = len(locks["locks"][brand])
20 | return brands
21 |
22 | def get_num_locks():
23 | num_locks = 0
24 | for brand in locks["locks"]:
25 | num_locks += len(locks["locks"][brand])
26 | return num_locks
27 |
28 | @main.route('/', methods=['POST'])
29 | @cross_origin()
30 | def get_lock():
31 | brand = str(request.form.get('brand'))
32 | brands = list_brands()
33 | num_locks = get_num_locks()
34 | models = locks["locks"][brand]
35 | return render_template('index.html', brands=brands, num_locks=num_locks, models=models)
36 |
--------------------------------------------------------------------------------
/app/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | ShareLocks
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
33 |
34 |
35 |
36 |
37 | {% block content %}
38 | {% endblock %}
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 | {% extends "base.html" %}
3 |
4 | {% block content %}
5 |
6 |
7 |
8 |
9 |
10 |
#locks: {{ num_locks }}
11 |
12 |
13 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | {% for model in models %}
36 |
37 |
38 | {% if models[model].difficulty == 'beginner' %}
39 |
40 | {% elif models[model].difficulty == 'intermediate' %}
41 |
42 | {% elif models[model].difficulty == 'expert' %}
43 |
44 | {% else %}
45 |
46 | {% endif %}
47 |
48 |  |
49 |
50 | Brand: {{models[model].brand}}
51 | Model: {{model}}
52 | Type: {{ models[model].type }}
53 | #Pins: {{ models[model].num_pins }}
54 | |
55 |
56 |
57 |
58 |
59 |
60 |
Difficulty:
61 | {% if models[model].difficulty == 'beginner' %}
62 |
63 | {% elif models[model].difficulty == 'intermediate' %}
64 |
65 | {% elif models[model].difficulty == 'expert' %}
66 |
67 | {% else %}
68 |
69 | {% endif %}
70 | {{ models[model].difficulty }}
71 |
72 |
73 |
74 |
75 | {% for method in models[model].opening_method %}
76 |
77 | | {{ method.name }} |
78 | {{ method.time }} |
79 |
80 | {% endfor %}
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | | Position |
90 | Shape |
91 | Confidence (%) |
92 |
93 |
94 |
95 | {% for pin in models[model].pins %}
96 | {% if pin.security == true %}
97 |
98 | {% else %}
99 |
100 | {% endif %}
101 |
102 | {% if pin.warning == true %}
103 | | {{ pin.position }} (*) |
104 | {% else %}
105 | {{ pin.position }} |
106 | {% endif %}
107 | {{ pin.shape }} |
108 | {{ pin.confidence }} |
109 |
110 | {% endfor %}
111 |
112 |
113 |
114 |
115 |
116 |
117 |
Tips:
118 |
119 |
120 | {% for tip in models[model].tips %}
121 | - {{ tip.content }}
122 | {% endfor %}
123 |
124 |
125 |
126 |
127 |
128 | {% endfor %}
129 |
130 |
131 |
132 |
133 |
134 | {% endblock %}
--------------------------------------------------------------------------------
/app/locks.json:
--------------------------------------------------------------------------------
1 | {
2 | "locks": {
3 | "ABUS": {
4 | "E50": {
5 | "brand": "ABUS",
6 | "picture": "ABUS_E50.png",
7 | "type": "paracentrique",
8 | "num_pins": 5,
9 | "pins": [
10 | {
11 | "position": 1,
12 | "shape": "spool",
13 | "confidence": 100,
14 | "security": true,
15 | "warning": false
16 | },
17 | {
18 | "position": 2,
19 | "shape": "regular",
20 | "confidence": 100,
21 | "security": false,
22 | "warning": false
23 | },
24 | {
25 | "position": 3,
26 | "shape": "spool",
27 | "confidence": 100,
28 | "security": true,
29 | "warning": true
30 | },
31 | {
32 | "position": 4,
33 | "shape": "spool",
34 | "confidence": 100,
35 | "security": true,
36 | "warning": false
37 | },
38 | {
39 | "position": 5,
40 | "shape": "spool",
41 | "confidence": 100,
42 | "security": true,
43 | "warning": false
44 | }
45 | ],
46 | "opening_method": [
47 | {
48 | "name": "single-pin-picking",
49 | "time": "< 5 min"
50 | }
51 | ],
52 | "difficulty": "intermediate",
53 | "tips": [
54 | {
55 | "content": "pins 3 is untouchable"
56 | }
57 | ]
58 | },
59 | "E60": {
60 | "brand": "ABUS",
61 | "picture": "ABUS_E60.png",
62 | "type": "paracentrique",
63 | "num_pins": 6,
64 | "pins": [
65 | {
66 | "position": 1,
67 | "shape": "spool",
68 | "confidence": 100,
69 | "security": true,
70 | "warning": false
71 | },
72 | {
73 | "position": 2,
74 | "shape": "regular",
75 | "confidence": 100,
76 | "security": false,
77 | "warning": false
78 | },
79 | {
80 | "position": 3,
81 | "shape": "spool",
82 | "confidence": 100,
83 | "security": true,
84 | "warning": false
85 | },
86 | {
87 | "position": 4,
88 | "shape": "?",
89 | "confidence": 100,
90 | "security": true,
91 | "warning": false
92 | },
93 | {
94 | "position": 5,
95 | "shape": "?",
96 | "confidence": 100,
97 | "security": true,
98 | "warning": false
99 | },
100 | {
101 | "position": 6,
102 | "shape": "regular",
103 | "confidence": 100,
104 | "security": false
105 | }
106 | ],
107 | "opening_method": [
108 | {
109 | "name": "single-pin-picking",
110 | "time": "< 20 min"
111 | }
112 | ],
113 | "difficulty": "expert",
114 | "tips": [
115 | {
116 | "content": ""
117 | }
118 | ]
119 | }
120 | },
121 | "BRICARD": {
122 | "alpha": {
123 | "brand": "BRICARD",
124 | "picture": "BRICARD_alpha.png",
125 | "type": "paracentrique",
126 | "num_pins": 5,
127 | "pins": [
128 | {
129 | "position": 1,
130 | "shape": "regular",
131 | "confidence": 100,
132 | "security": false,
133 | "warning": false
134 | },
135 | {
136 | "position": 2,
137 | "shape": "spool",
138 | "confidence": 50,
139 | "security": true,
140 | "warning": false
141 | },
142 | {
143 | "position": 3,
144 | "shape": "spool",
145 | "confidence": 50,
146 | "security": true,
147 | "warning": true
148 | },
149 | {
150 | "position": 4,
151 | "shape": "spool",
152 | "confidence": 50,
153 | "security": true,
154 | "warning": false
155 | },
156 | {
157 | "position": 5,
158 | "shape": "spool",
159 | "confidence": 50,
160 | "security": true,
161 | "warning": false
162 | }
163 | ],
164 | "opening_method": [
165 | {
166 | "name": "single-pin-picking",
167 | "time": "< 5 min"
168 | }
169 | ],
170 | "difficulty": "intermediate",
171 | "tips": [
172 | {
173 | "content": "pins 3 is untouchable"
174 | }
175 | ]
176 | }
177 | },
178 | "MASTER": {
179 | "security_20mm": {
180 | "brand": "MASTER",
181 | "picture": "MASTER_security_20mm.png",
182 | "type": "paracentrique",
183 | "num_pins": 4,
184 | "pins": [
185 | {
186 | "position": 1,
187 | "shape": "regular",
188 | "confidence": 100,
189 | "security": false,
190 | "warning": false
191 | },
192 | {
193 | "position": 2,
194 | "shape": "regular",
195 | "confidence": 100,
196 | "security": false,
197 | "warning": false
198 | },
199 | {
200 | "position": 3,
201 | "shape": "regular",
202 | "confidence": 100,
203 | "security": false,
204 | "warning": false
205 | },
206 | {
207 | "position": 4,
208 | "shape": "regular",
209 | "confidence": 100,
210 | "security": false,
211 | "warning": false
212 | }
213 | ],
214 | "opening_method": [
215 | {
216 | "name": "racking",
217 | "time": "< 30 s"
218 | }
219 | ],
220 | "difficulty": "beginner",
221 | "tips": [
222 | {
223 | "content": "Use a 'snake' pick"
224 | }
225 | ]
226 | },
227 | "security_40mm": {
228 | "brand": "MASTER",
229 | "picture": "MASTER_security_40mm.png",
230 | "type": "paracentrique",
231 | "num_pins": 5,
232 | "pins": [
233 | {
234 | "position": 1,
235 | "shape": "regular",
236 | "confidence": 100,
237 | "security": false,
238 | "warning": false
239 | },
240 | {
241 | "position": 2,
242 | "shape": "regular",
243 | "confidence": 100,
244 | "security": false,
245 | "warning": false
246 | },
247 | {
248 | "position": 3,
249 | "shape": "regular",
250 | "confidence": 100,
251 | "security": false,
252 | "warning": false
253 | },
254 | {
255 | "position": 4,
256 | "shape": "regular",
257 | "confidence": 100,
258 | "security": false,
259 | "warning": true
260 | },
261 | {
262 | "position": 5,
263 | "shape": "regular",
264 | "confidence": 100,
265 | "security": false,
266 | "warning": true
267 | }
268 | ],
269 | "opening_method": [
270 | {
271 | "name": "racking",
272 | "time": "< 30 s"
273 | }
274 | ],
275 | "difficulty": "beginner",
276 | "tips": [
277 | {
278 | "content": "The last 2 pins are relevants"
279 | }
280 | ]
281 | }
282 | },
283 | "THIRARD": {
284 | "unknown_1": {
285 | "brand": "THIRARD",
286 | "picture": "THIRARD_unknown_1.png",
287 | "type": "paracentrique",
288 | "num_pins": 5,
289 | "pins": [
290 | {
291 | "position": 1,
292 | "shape": "regular",
293 | "confidence": 100,
294 | "security": false,
295 | "warning": false
296 | },
297 | {
298 | "position": 2,
299 | "shape": "regular",
300 | "confidence": 100,
301 | "security": false,
302 | "warning": false
303 | },
304 | {
305 | "position": 3,
306 | "shape": "regular",
307 | "confidence": 100,
308 | "security": false,
309 | "warning": false
310 | },
311 | {
312 | "position": 4,
313 | "shape": "regular",
314 | "confidence": 100,
315 | "security": false,
316 | "warning": false
317 | },
318 | {
319 | "position": 5,
320 | "shape": "regular",
321 | "confidence": 100,
322 | "security": false,
323 | "warning": false
324 | }
325 | ],
326 | "opening_method": [
327 | {
328 | "name": "racking",
329 | "time": "< 3 min"
330 | },
331 | {
332 | "name": "single-pin-picking",
333 | "time": "< 5 min"
334 | }
335 | ],
336 | "difficulty": "beginner",
337 | "tips": [
338 | {
339 | "content": ""
340 | }
341 | ]
342 | }
343 | },
344 | "YELLOW_LINE": {
345 | "unknown_1": {
346 | "brand": "YELLOW LINE (CYL)",
347 | "picture": "YELLOW_LINE_unknown_1.png",
348 | "type": "paracentrique",
349 | "num_pins": 6,
350 | "pins": [
351 | {
352 | "position": 1,
353 | "shape": "regular",
354 | "confidence": 100,
355 | "security": false,
356 | "warning": false
357 | },
358 | {
359 | "position": 2,
360 | "shape": "regular",
361 | "confidence": 100,
362 | "security": false,
363 | "warning": false
364 | },
365 | {
366 | "position": 3,
367 | "shape": "regular",
368 | "confidence": 100,
369 | "security": false,
370 | "warning": false
371 | },
372 | {
373 | "position": 4,
374 | "shape": "regular",
375 | "confidence": 100,
376 | "security": false,
377 | "warning": false
378 | },
379 | {
380 | "position": 5,
381 | "shape": "regular",
382 | "confidence": 100,
383 | "security": false,
384 | "warning": false
385 | },
386 | {
387 | "position": 6,
388 | "shape": "regular",
389 | "confidence": 100,
390 | "security": false,
391 | "warning": false
392 | }
393 | ],
394 | "opening_method": [
395 | {
396 | "name": "racking",
397 | "time": "< 1 min"
398 | },
399 | {
400 | "name": "single-pin-picking",
401 | "time": "< 5 min"
402 | }
403 | ],
404 | "difficulty": "beginner",
405 | "tips": [
406 | {
407 | "content": "The relevant pins are at the bottom of the lock. Do not touch the first pins."
408 | }
409 | ]
410 | },
411 | "unknown_2": {
412 | "brand": "YELLOW LINE (CYL)",
413 | "picture": "YELLOW_LINE_unknown_2.png",
414 | "type": "paracentrique",
415 | "num_pins": 5,
416 | "pins": [
417 | {
418 | "position": 1,
419 | "shape": "regular",
420 | "confidence": 100,
421 | "security": false,
422 | "warning": false
423 | },
424 | {
425 | "position": 2,
426 | "shape": "regular",
427 | "confidence": 100,
428 | "security": false,
429 | "warning": false
430 | },
431 | {
432 | "position": 3,
433 | "shape": "regular",
434 | "confidence": 100,
435 | "security": false,
436 | "warning": false
437 | },
438 | {
439 | "position": 4,
440 | "shape": "regular",
441 | "confidence": 100,
442 | "security": false,
443 | "warning": false
444 | },
445 | {
446 | "position": 5,
447 | "shape": "regular",
448 | "confidence": 100,
449 | "security": false,
450 | "warning": false
451 | }
452 | ],
453 | "opening_method": [
454 | {
455 | "name": "racking",
456 | "time": "< 1 min"
457 | }
458 | ],
459 | "difficulty": "beginner",
460 | "tips": [
461 | {
462 | "content": "Just rack the pins slowly"
463 | }
464 | ]
465 | }
466 | }
467 | }
468 | }
--------------------------------------------------------------------------------