├── Procfile ├── app ├── __init__.py ├── locks.json ├── main.py ├── static │ ├── images │ │ └── locks │ │ │ ├── ABUS_E50.png │ │ │ ├── ABUS_E60.png │ │ │ ├── BRICARD_alpha.png │ │ │ ├── MASTER_security_20mm.png │ │ │ ├── MASTER_security_40mm.png │ │ │ ├── THIRARD_unknown_1.png │ │ │ ├── YELLOW_LINE_unknown_1.png │ │ │ └── YELLOW_LINE_unknown_2.png │ └── js │ │ └── letmein.js └── templates │ ├── base.html │ └── index.html ├── images └── screen.png ├── readme.md ├── requirements.txt └── runtime.txt /Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn "app:create_app()" 2 | -------------------------------------------------------------------------------- /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/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 | } -------------------------------------------------------------------------------- /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/static/images/locks/ABUS_E50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellchocolat/ShareLocks/250516fd8371192ba81ec995f1c9bae09edc4539/app/static/images/locks/ABUS_E50.png -------------------------------------------------------------------------------- /app/static/images/locks/ABUS_E60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellchocolat/ShareLocks/250516fd8371192ba81ec995f1c9bae09edc4539/app/static/images/locks/ABUS_E60.png -------------------------------------------------------------------------------- /app/static/images/locks/BRICARD_alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellchocolat/ShareLocks/250516fd8371192ba81ec995f1c9bae09edc4539/app/static/images/locks/BRICARD_alpha.png -------------------------------------------------------------------------------- /app/static/images/locks/MASTER_security_20mm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellchocolat/ShareLocks/250516fd8371192ba81ec995f1c9bae09edc4539/app/static/images/locks/MASTER_security_20mm.png -------------------------------------------------------------------------------- /app/static/images/locks/MASTER_security_40mm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellchocolat/ShareLocks/250516fd8371192ba81ec995f1c9bae09edc4539/app/static/images/locks/MASTER_security_40mm.png -------------------------------------------------------------------------------- /app/static/images/locks/THIRARD_unknown_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellchocolat/ShareLocks/250516fd8371192ba81ec995f1c9bae09edc4539/app/static/images/locks/THIRARD_unknown_1.png -------------------------------------------------------------------------------- /app/static/images/locks/YELLOW_LINE_unknown_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellchocolat/ShareLocks/250516fd8371192ba81ec995f1c9bae09edc4539/app/static/images/locks/YELLOW_LINE_unknown_1.png -------------------------------------------------------------------------------- /app/static/images/locks/YELLOW_LINE_unknown_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellchocolat/ShareLocks/250516fd8371192ba81ec995f1c9bae09edc4539/app/static/images/locks/YELLOW_LINE_unknown_2.png -------------------------------------------------------------------------------- /app/static/js/letmein.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellchocolat/ShareLocks/250516fd8371192ba81ec995f1c9bae09edc4539/app/static/js/letmein.js -------------------------------------------------------------------------------- /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 |
14 |
15 |
16 | 22 |
23 |
24 | 25 |
26 | 27 |
28 |
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 | 55 | 56 |
image not found 50 |
Brand: {{models[model].brand}}
51 |
Model: {{model}}
52 |
Type: {{ models[model].type }}
53 |
#Pins: {{ models[model].num_pins }}
54 |
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 | 78 | 79 | 80 | {% endfor %} 81 | 82 |
{{ method.name }}{{ method.time }}
83 |
84 | 85 |
86 | 87 | 88 | 89 | 90 | 91 | 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 | 104 | {% else %} 105 | 106 | {% endif %} 107 | 108 | 109 | 110 | {% endfor %} 111 | 112 |
PositionShapeConfidence (%)
{{ pin.position }} (*){{ pin.position }}{{ pin.shape }}{{ pin.confidence }}
113 | 114 |
115 | 116 |
117 |
Tips:
118 |
119 |
    120 | {% for tip in models[model].tips %} 121 |
  1. {{ tip.content }}
  2. 122 | {% endfor %} 123 |
124 |
125 |
126 | 127 |
128 | {% endfor %} 129 | 130 |
131 |
132 | 133 | 134 | {% endblock %} -------------------------------------------------------------------------------- /images/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shellchocolat/ShareLocks/250516fd8371192ba81ec995f1c9bae09edc4539/images/screen.png -------------------------------------------------------------------------------- /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 | ![](images/screen.png) 22 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.10.4 2 | --------------------------------------------------------------------------------