├── crts
└── index.html
├── .gitignore
├── requirements.txt
├── env_variables
├── Dockerfile
├── README.md
└── pyawal.py
/crts/index.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | env_variables
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==1.0.2
2 | wallet_py3k==0.0.4
3 | python-barcode==0.13.1
4 | Pillow==8.1.2
5 | requests==2.25.1
--------------------------------------------------------------------------------
/env_variables:
--------------------------------------------------------------------------------
1 | export PASS_TYPE_IDENT=pass.identity
2 | export TEAM_IDENT=teamident
3 | export PASS_PASSWORD=certpasswords
4 | export PRD_ADDRESS="https://wallet.domain.com"
5 | export DEV_ADDRESS="http://192.168.0.101"
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.7-alpine
2 |
3 | RUN apk upgrade --update-cache --available && \
4 | apk add openssl ca-certificates zlib-dev jpeg-dev gcc musl-dev --no-cache g++ freetype-dev jpeg-dev && \
5 | rm -rf /var/cache/apk/*
6 |
7 | WORKDIR /app
8 | COPY . .
9 |
10 | RUN pip install -r /app/requirements.txt
11 |
12 | VOLUME /app/crts
13 |
14 | EXPOSE 5002
15 |
16 | CMD [ "python", "/app/pyawal.py" ]
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Instructions:
2 | Make sure you have the required certs inside of the directory you mount below named exactly as so
3 |
4 | ```
5 | certificate.pem
6 | key.pem
7 | wwdr.pem
8 | ```
9 |
10 | ## Docker Compose Example:
11 | ```
12 | services:
13 | applewallet:
14 | image: shauder/apple-wallet-shortcut:latest
15 | container_name: applewallet
16 | restart: unless-stopped
17 | networks:
18 | - backend
19 | environment:
20 | - TZ=${TIME_ZONE}
21 | - PASS_TYPE_IDENT=certpassidentity
22 | - TEAM_IDENT=certteamid
23 | - PASS_PASSWORD=mysupersecretpasswordforcert
24 | - RETURN_ADDRESS=https://wallet.shane.app
25 | volumes:
26 | - /etc/localtime:/etc/localtime:ro
27 | - /data/docker/applewallet:/app/crts
28 | ```
--------------------------------------------------------------------------------
/pyawal.py:
--------------------------------------------------------------------------------
1 | import re
2 | import mimetypes
3 | import os
4 | import barcode
5 | import base64
6 | import requests
7 | from urllib.parse import unquote_plus
8 | from io import BytesIO
9 | from PIL import Image
10 | from barcode import Code39
11 | from barcode.writer import ImageWriter
12 | from flask import (
13 | Flask,
14 | redirect,
15 | request,
16 | render_template,
17 | send_file
18 | )
19 | from wallet.models import Pass, Barcode, StoreCard
20 |
21 | GENERIC_PASS_URL = 'https://www.icloud.com/shortcuts/70e4911a049045eea3cfd32d3d9908e6'
22 |
23 | pass_type_id = os.environ.get('PASS_TYPE_IDENT')
24 | team_id = os.environ.get('TEAM_IDENT')
25 | pass_passcode = os.environ.get('PASS_PASSWORD')
26 | prd_address = os.environ.get('PRD_ADDRESS')
27 | dev_address = os.environ.get('DEV_ADDRESS')
28 |
29 | if os.environ.get('PRODUCTION'):
30 | develop = False
31 | address = prd_address
32 | app_port = '5002'
33 | return_url = address
34 | else:
35 | develop = True
36 | address = dev_address
37 | app_port = '5002'
38 | return_url = address + ':' + app_port
39 |
40 | # Create the application instance
41 | app = Flask(__name__, template_folder='templates', static_url_path='')
42 |
43 | # Create a URL route in our application for '/'
44 | @app.route('/')
45 | def home():
46 | return redirect(GENERIC_PASS_URL, code=302)
47 |
48 | @app.route('/api/v1/ip', methods=['POST', 'GET'])
49 | def get_ext_ip():
50 | return requests.get('https://checkip.amazonaws.com').text.strip()
51 |
52 | @app.route('/api/v1//', methods=['POST', 'GET'])
53 | def gen_apple_wallet(barcode_type, barcode_input):
54 |
55 | if request.method == 'POST':
56 | if request.is_json:
57 | content = request.get_json(silent=False)
58 | else:
59 | content = { 'name': 'Membership Card' }
60 |
61 | elif request.method == 'GET':
62 | if request.is_json:
63 | content = request.get_json(silent=False)
64 | else:
65 | content = request.args
66 |
67 | else:
68 | return 'Bad request.'
69 |
70 | pass_name = decode_input(content.get('name', 'Membership Card'))
71 | pass_description = decode_input(content.get('description', 'My membership card ' + barcode_type + ' pass'))
72 | pass_header_text = decode_input(content.get('header_text'))
73 | pass_header_value = decode_input(content.get('header_value'))
74 | pass_primary_text = decode_input(content.get('primary_text'))
75 | pass_primary_value = decode_input(content.get('primary_value'))
76 | pass_icon = decode_input(content.get('icon', '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'))
77 | pass_logo = decode_input(content.get('logo', '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'))
78 | pass_location = decode_input(content.get('location', False))
79 | pass_latitude = decode_input(content.get('latitude', '0'))
80 | pass_longitude = decode_input(content.get('longitude', '0'))
81 | pass_relevant_text = decode_input(content.get('relevant_text', 'A pass is available for use here'))
82 | pass_foreground_color = decode_input(content.get('foreground_color', 'rgb(0,0,0)'))
83 | pass_background_color = decode_input(content.get('background_color', 'rgb(37,170,225)'))
84 | pass_label_color = decode_input(content.get('label_color', 'rgb(241,92,34)'))
85 |
86 | pass_debug = content.get('debug', False)
87 |
88 | if pass_debug:
89 | print(pass_name)
90 | print(pass_description)
91 | print(pass_icon)
92 | print(pass_logo)
93 | print(pass_location)
94 | print(pass_latitude)
95 | print(pass_longitude)
96 | print(pass_relevant_text)
97 | print(pass_foreground_color)
98 | print(pass_background_color)
99 | print(pass_label_color)
100 |
101 | simplename = re.sub('[^a-zA-Z0-9]', '', pass_name).lower()
102 |
103 | if barcode_type.upper() == 'C39':
104 | if len(barcode_input) < 44:
105 | pass_barcode_buffer = BytesIO()
106 | AW_C39 = barcode.get_barcode_class('Code39')
107 | AW_C39(barcode_input, writer=ImageWriter(), add_checksum=False).render({'font_size': 0, 'dpi': 300}).save(pass_barcode_buffer, format='PNG')
108 | pass_barcode = base64.b64encode(pass_barcode_buffer.getvalue())
109 | else:
110 | return 'Bad Code39 code.'
111 | elif barcode_type.upper() == 'C128':
112 | if len(barcode_input) < 129:
113 | pass_barcode_buffer = BytesIO()
114 | AW_C128 = barcode.get_barcode_class('Code128')
115 | AW_C128(barcode_input, writer=ImageWriter()).render({'font_size': 0, 'dpi': 300}).save(pass_barcode_buffer, format='PNG')
116 | pass_barcode = base64.b64encode(pass_barcode_buffer.getvalue())
117 | else:
118 | return 'Bad Code128 code.'
119 | elif barcode_type.upper() == 'EAN13':
120 | barcode_input = re.sub("\D", "", barcode_input)
121 | if len(barcode_input) == 13:
122 | pass_barcode_buffer = BytesIO()
123 | AW_EAN13 = barcode.get_barcode_class('EAN13')
124 | AW_EAN13(barcode_input, writer=ImageWriter()).render({'font_size': 0, 'dpi': 300}).save(pass_barcode_buffer, format='PNG')
125 | pass_barcode = base64.b64encode(pass_barcode_buffer.getvalue())
126 | else:
127 | return 'Bad EAN13 code.'
128 | elif barcode_type.upper() == 'EAN8':
129 | barcode_input = re.sub("\D", "", barcode_input)
130 | if len(barcode_input) == 8:
131 | pass_barcode_buffer = BytesIO()
132 | AW_EAN8 = barcode.get_barcode_class('EAN8')
133 | AW_EAN8(barcode_input, writer=ImageWriter()).render({'font_size': 0, 'dpi': 300}).save(pass_barcode_buffer, format='PNG')
134 | pass_barcode = base64.b64encode(pass_barcode_buffer.getvalue())
135 | else:
136 | return 'Bad EAN8 code.'
137 | elif barcode_type.upper() == 'JAN':
138 | barcode_input = re.sub("\D", "", barcode_input)
139 | if ( barcode_input[0:2] == '45' or barcode_input[0:2] == '49' ) and len(barcode_input) == 13:
140 | pass_barcode_buffer = BytesIO()
141 | AW_JAN = barcode.get_barcode_class('JAN')
142 | AW_JAN(barcode_input, writer=ImageWriter()).render({'font_size': 0, 'dpi': 300}).save(pass_barcode_buffer, format='PNG')
143 | pass_barcode = base64.b64encode(pass_barcode_buffer.getvalue())
144 | else:
145 | return 'Bad JAN code.'
146 | elif barcode_type.upper() == 'ISBN13':
147 | barcode_input = re.sub("\D", "", barcode_input)
148 | if ( barcode_input[0:3] == '978' or barcode_input[0:3] == '979' ) and len(barcode_input) == 13:
149 | pass_barcode_buffer = BytesIO()
150 | AW_ISBN13 = barcode.get_barcode_class('ISBN13')
151 | AW_ISBN13(barcode_input, writer=ImageWriter()).render({'font_size': 0, 'dpi': 300}).save(pass_barcode_buffer, format='PNG')
152 | pass_barcode = base64.b64encode(pass_barcode_buffer.getvalue())
153 | else:
154 | return 'Bad ISBN13 code.'
155 | elif barcode_type.upper() == 'ISBN10':
156 | barcode_input = re.sub("\D", "", barcode_input)
157 | if len(barcode_input) == 10:
158 | pass_barcode_buffer = BytesIO()
159 | AW_ISBN10= barcode.get_barcode_class('ISBN10')
160 | AW_ISBN10(barcode_input, writer=ImageWriter()).render({'font_size': 0, 'dpi': 300}).save(pass_barcode_buffer, format='PNG')
161 | pass_barcode = base64.b64encode(pass_barcode_buffer.getvalue())
162 | else:
163 | return 'Bad ISBN10 code.'
164 | elif barcode_type.upper() == 'ISSN':
165 | barcode_input = re.sub("\D", "", barcode_input)
166 | if len(barcode_input) == 8:
167 | pass_barcode_buffer = BytesIO()
168 | AW_ISSN= barcode.get_barcode_class('ISSN')
169 | AW_ISSN(barcode_input, writer=ImageWriter()).render({'font_size': 0, 'dpi': 300}).save(pass_barcode_buffer, format='PNG')
170 | pass_barcode = base64.b64encode(pass_barcode_buffer.getvalue())
171 | else:
172 | return 'Bad ISSN code.'
173 | elif barcode_type.upper() == 'NOCODE':
174 | pass_barcode = None
175 | else:
176 | return 'No valid barcode type passed with the request, try again.'
177 |
178 | cardInfo = StoreCard()
179 |
180 | if not barcode_type.upper() == 'NOCODE' and not pass_header_text and not pass_header_value:
181 | pass_header_text = 'Account Number'
182 | pass_header_value = barcode_input
183 |
184 | if pass_header_text and pass_header_value:
185 | cardInfo.addHeaderField('header_field', pass_header_value, pass_header_text)
186 |
187 | if barcode_type.upper() == 'NOCODE' and pass_primary_value and pass_primary_text:
188 | cardInfo.addPrimaryField('primary_field', pass_primary_value, pass_primary_text)
189 |
190 | cardInfo.addBackField('name', pass_name, 'Name: ')
191 | cardInfo.addBackField('description', pass_description, 'Description: ')
192 | cardInfo.addBackField('credit', address, 'Created By: ')
193 |
194 | passfile = Pass(cardInfo, \
195 | passTypeIdentifier=pass_type_id, \
196 | organizationName=pass_name, \
197 | teamIdentifier=team_id)
198 |
199 | passfile.logoText = pass_name
200 | passfile.description = pass_description
201 | passfile.serialNumber = pass_type_id + '.' + simplename + '.' + barcode_input
202 | passfile.barcode = ''
203 | passfile.foregroundColor = pass_foreground_color
204 | passfile.backgroundColor = pass_background_color
205 | passfile.labelColor = pass_label_color
206 |
207 | if pass_location:
208 | passfile.locations = [{'latitude' : float(pass_latitude), 'longitude' : float(pass_longitude), 'relevantText' : pass_relevant_text}]
209 |
210 | passfile.addFile('icon.png', BytesIO(base64.b64decode(str(pass_icon))))
211 | passfile.addFile('logo.png', BytesIO(base64.b64decode(str(pass_logo))))
212 |
213 | if not barcode_type.upper() == 'NOCODE':
214 | passfile.addFile('strip.png', BytesIO(base64.b64decode(pass_barcode)))
215 |
216 | pass_encoded = base64.b64encode(passfile.create('crts/certificate.pem', 'crts/key.pem', 'crts/wwdr.pem', pass_passcode).getvalue())
217 |
218 | return send_file(BytesIO(base64.b64decode(pass_encoded)), mimetype='application/vnd.apple.pkpass', as_attachment=True, attachment_filename='pass.pkpass')
219 |
220 | def decode_input(input_text):
221 | if input_text:
222 | if '%2B' in input_text or '%3D' in input_text or '%2F' in input_text:
223 | return unquote_plus(input_text)
224 | else:
225 | return input_text
226 |
227 | def main():
228 | mimetypes.add_type('application/vnd.apple.pkpass', '.pkpass')
229 | app.run(host='0.0.0.0', port=app_port, debug=False)
230 |
231 | # If we're running in stand alone mode, run the application
232 | if __name__ == '__main__':
233 | main()
234 |
--------------------------------------------------------------------------------