ass 0.0.21 → 0.0.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (8) hide show
  1. checksums.yaml +15 -0
  2. data/README.md +14 -2
  3. data/VERSION +1 -1
  4. data/ass.yml +3 -1
  5. data/lib/ass.rb +2 -404
  6. data/lib/ass/app.rb +277 -0
  7. data/lib/ass/conf.rb +165 -0
  8. metadata +57 -86
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZTA5ZjhkMzc5ZjFlNThiNzQ3YjExOGJiMTI4MmJmMDEzNjU3MjFlYg==
5
+ data.tar.gz: !binary |-
6
+ NTJjOGI2M2IyMGI2NTUyNTcwYTFiZTNmYjhkODBkZjUxOGVmMWNkZA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NmFhYjAzNGJmZTA4MmYwOGJkMDU2ZWFiMjMyZWM4YzUwNmZlNTdiYTcyYzk3
10
+ MmI5ZjYzMGY3Y2U0MTYwYzI4MWRjYjMxNWNiNTRkYWMxMTU1OTFjMDdkYmRl
11
+ MDQ5NmUwNjZiMTZjNGUxMWRmN2UyZjdlOTNiMjkwNWM2YzIxN2E=
12
+ data.tar.gz: !binary |-
13
+ ZmI4NTFiMDdjNDQ4YTU2Y2ZjYWNiNTA1MDYzYTM1ODZkNWIxNTE2NGFiZTQ0
14
+ MTc5NmY1ZGJlYjg4YTViN2RkMTllYjNmNGQ2NjA3YWJlOWNmMTQ4M2U0OGY2
15
+ OGJlNjlkYjJkMzI0YjNmZDUxNmNjOGY2MGNkMjVkY2JmZTc4NmQ=
data/README.md CHANGED
@@ -116,6 +116,9 @@ when you run 'ass' first time, it will generate 'ass.yml' config file under curr
116
116
  timer: 0 # how often you run the cron job, unit: minute. when set with 0, means no cron job execute.
117
117
  user: admin # admin username
118
118
  pass: pass # admin password
119
+ flood: 1 # request time from same ip every one minute as Flood Attack
120
+ pempass: pempass # pem password
121
+ loglevel: info # logger level
119
122
  apps:
120
123
  - app1 ## appid you want to supprt APNS, ASS Server can give push notification support for many iOS apps, just list the appid here.
121
124
 
@@ -156,13 +159,11 @@ In AppDelegate file, add methods below to register device token
156
159
 
157
160
  - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
158
161
 
159
- if ([((AppDelegate *) [[UIApplication sharedApplication] delegate]) checkNetwork1]) {
160
162
  NSString *tokenAsString = [[[deviceToken description]
161
163
  stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]]
162
164
  stringByReplacingOccurrencesOfString:@" " withString:@""];
163
165
  NSLog(@"My token is: [%@]", tokenAsString);
164
166
  [self sendToken:tokenAsString];
165
- }
166
167
 
167
168
  }
168
169
 
@@ -211,6 +212,17 @@ open your web browser and access http://localhost:4567/ (localhost should be cha
211
212
 
212
213
  ![ass usage](https://raw.github.com/eiffelqiu/ass/master/doc/capture5.png)
213
214
 
215
+ 4. How to run ass in background?
216
+ -------
217
+
218
+ $ nohup ass
219
+
220
+ control + z to return to shell prompt
221
+
222
+ $ bg
223
+
224
+ now ass is running as a background service .
225
+
214
226
  Contributing to ass
215
227
  =======
216
228
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.21
1
+ 0.0.24
data/ass.yml CHANGED
@@ -3,8 +3,10 @@ mode: development
3
3
  log: off
4
4
  cron: cron
5
5
  timer: 0
6
- user: admim
6
+ user: admin
7
7
  pass: pass
8
8
  flood: 1
9
+ pempass: pempass
10
+ loglevel: info
9
11
  apps:
10
12
  - app1
data/lib/ass.rb CHANGED
@@ -1,406 +1,4 @@
1
1
  #encoding: utf-8
2
2
 
3
- require 'rubygems'
4
- require 'sinatra'
5
- require 'sequel'
6
- require 'socket'
7
- require 'openssl'
8
- require 'cgi'
9
- require 'rufus/scheduler'
10
- require 'eventmachine'
11
- require 'sinatra/base'
12
- require 'rack/mobile-detect'
13
- require 'yaml'
14
- require 'uri-handler'
15
- require 'net/http'
16
- require 'active_support'
17
- require 'json'
18
- require 'digest/sha2'
19
- require 'will_paginate'
20
- require 'will_paginate/sequel' # or data_mapper/sequel
21
- require 'uri'
22
- require 'sinatra/reloader' if development?
23
- require 'sinatra/synchrony'
24
-
25
- ############################################################
26
- ## Initilization Setup
27
- ############################################################
28
- LIBDIR = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
29
- ROOTDIR = File.expand_path(File.join(File.dirname(__FILE__), '..'))
30
- unless $LOAD_PATH.include?(LIBDIR)
31
- $LOAD_PATH << LIBDIR
32
- end
33
-
34
- unless File.exist?("#{Dir.pwd}/ass.yml") then
35
- puts 'create config file: ass.yml'
36
- system "cp #{ROOTDIR}/ass.yml #{Dir.pwd}/ass.yml"
37
- end
38
-
39
- unless File.exist?("#{Dir.pwd}/cron") then
40
- puts "create a demo 'cron' script"
41
- system "cp #{ROOTDIR}/cron #{Dir.pwd}/cron"
42
- end
43
-
44
- ############################################################
45
- ## Configuration Setup
46
- ############################################################
47
- env = ENV['SINATRA_ENV'] || "development"
48
- config = YAML.load_file("#{Dir.pwd}/ass.yml")
49
- $timer = "#{config['timer']}".to_i
50
- $cron = config['cron'] || 'cron'
51
- $port = "#{config['port']}".to_i || 4567
52
- $mode = config['mode'] || env
53
- $VERSION = File.open("#{ROOTDIR}/VERSION", "rb").read
54
- $apps = config['apps'] || []
55
- $log = config['log'] || 'off'
56
- $user = config['user'] || 'admin'
57
- $pass = config['pass'] || 'pass'
58
- $flood = "#{config['flood']}".to_i || 1 # default 1 minute
59
-
60
- $client_ip = '127.0.0.1'
61
- $last_access = 0
62
-
63
- ############################################################
64
- ## Certificate Key Setup
65
- ############################################################
66
-
67
- $certkey = {}
68
-
69
- def check_cert
70
- $apps.each { |app|
71
- unless File.exist?("#{Dir.pwd}/#{app}_#{$mode}.pem") then
72
- puts "Please provide #{app}_#{$mode}.pem under '#{Dir.pwd}/' directory"
73
- return false;
74
- else
75
- puts "'#{app}'s #{$mode} PEM: (#{app}_#{$mode}.pem)"
76
- certfile = File.read("#{Dir.pwd}/#{app}_#{$mode}.pem")
77
- openSSLContext = OpenSSL::SSL::SSLContext.new
78
- openSSLContext.cert = OpenSSL::X509::Certificate.new(certfile)
79
- openSSLContext.key = OpenSSL::PKey::RSA.new(certfile)
80
- $certkey["#{app}"] = openSSLContext
81
- end
82
- }
83
- return true
84
- end
85
-
86
- unless check_cert then
87
- html = <<-END
88
- 1: please provide certificate key pem file under current directory, name should be: appid_development.pem for development and appid_production.pem for production
89
- 2: edit your ass.yml under current directory
90
- 3: run ass
91
- 4: iOS Client: in AppDelegate file, didRegisterForRemoteNotificationsWithDeviceToken method should access url below:
92
- END
93
- $apps.each { |app|
94
- html << "'#{app}'s registration url: http://serverIP:#{$port}/v1/apps/#{app}/DeviceToken"
95
- }
96
- html << "5: Server: cron should access 'curl http://localhost:#{$port}/v1/app/push/{messages}/{pid}' to send push message"
97
- puts html
98
- exit
99
- else
100
- html = <<-END
101
- #{'*'*80}
102
- Apple Service Server(#{$VERSION}) is Running ...
103
- Push Notification Service: Enabled
104
- Mode: #{$mode}
105
- Port: #{$port}
106
- END
107
- html << "#{'*'*80}"
108
- html << "Cron Job: '#{Dir.pwd}/#{$cron}' script is running every #{$timer} #{($timer == 1) ? 'minute' : 'minutes'} " unless "#{$timer}".to_i == 0
109
- html << "\n"
110
- html << "access http://localhost:#{$port}/ for more information"
111
- html << "\n"
112
- html << "#{'*'*80}"
113
- puts html
114
- end
115
-
116
- ############################################################
117
- ## Sequel Database Setup
118
- ############################################################
119
-
120
- unless File.exist?("#{Dir.pwd}/ass-#{$mode}.db") then
121
- $DB = Sequel.connect("sqlite://#{Dir.pwd}/ass-#{$mode}.db")
122
- $DB.create_table :tokens do
123
- primary_key :id
124
- String :app, :unique => false, :null => false
125
- String :token, :unique => false, :null => false, :size => 100
126
- Time :created_at
127
- index [:app, :token]
128
- end
129
- $DB.create_table :pushes do
130
- primary_key :id
131
- String :pid, :unique => false, :null => false, :size => 100
132
- String :app, :unique => false, :null => false, :size => 30
133
- String :message, :unique => false, :null => false, :size => 107
134
- Time :created_at
135
- index [:pid, :app, :message]
136
- end
137
- else
138
- $DB = Sequel.connect("sqlite://#{Dir.pwd}/ass-#{$mode}.db")
139
- end
140
-
141
- WillPaginate.per_page = 10
142
-
143
- class Token < Sequel::Model
144
- Sequel.extension :pagination
145
- end
146
-
147
- class Push < Sequel::Model
148
- Sequel.extension :pagination
149
- end
150
-
151
- ############################################################
152
- ## Timer Job Setup
153
- ############################################################
154
- scheduler = Rufus::Scheduler.start_new
155
-
156
- unless $timer == 0 then
157
- scheduler.every "#{$timer}m" do
158
- puts "running job: '#{Dir.pwd}/#{$cron}' every #{$timer} #{($timer == 1) ? 'minute' : 'minutes'}"
159
- system "./#{$cron}"
160
- end
161
- end
162
-
163
- ############################################################
164
- ## Apple Service Server based on Sinatra
165
- ############################################################
166
-
167
- class App < Sinatra::Base
168
-
169
- register Sinatra::Synchrony
170
-
171
- use Rack::MobileDetect
172
-
173
- set :root, File.expand_path('../../', __FILE__)
174
- set :port, "#{$port}".to_i
175
- set :public_folder, File.dirname(__FILE__) + '/../public'
176
- set :views, File.dirname(__FILE__) + '/../views'
177
-
178
- helpers do
179
-
180
- def checkFlood?(req)
181
- if $client_ip != "#{req.ip}" then
182
- $client_ip = "#{req.ip}"
183
- return false
184
- else
185
- if $last_access == 0 then
186
- return false
187
- else
188
- return isFlood?
189
- end
190
- end
191
- end
192
-
193
- def isFlood?
194
- result = (Time.now - $last_access) < $flood * 60
195
- $last_access = Time.now
196
- return result
197
- end
198
-
199
- def iOS?
200
- result = case request.env['X_MOBILE_DEVICE']
201
- when /iPhone|iPod|iPad/ then
202
- true
203
- else false
204
- end
205
- return result
206
- end
207
-
208
- def authorized?
209
- @auth ||= Rack::Auth::Basic::Request.new(request.env)
210
- @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ["#{$user}", "#{$pass}"]
211
- end
212
-
213
- def protected!
214
- unless authorized?
215
- response['WWW-Authenticate'] = %(Basic realm="Restricted Area")
216
- throw(:halt, [401, "Oops... we need your login name & password\n"])
217
- end
218
- end
219
- end
220
-
221
- configure :production, :development do
222
- if "#{$log}".strip == 'on' then
223
- enable :logging
224
- end
225
- end
226
-
227
- if "#{$mode}".strip == 'development' then
228
- set :show_exceptions, true
229
- set :dump_errors, true
230
- else
231
- set :show_exceptions, false
232
- set :dump_errors, false
233
- end
234
-
235
- get '/' do
236
- erb :index
237
- end
238
-
239
- get '/about' do
240
- erb :about
241
- end
242
-
243
- not_found do
244
- erb :not_found
245
- end
246
-
247
- error do
248
- @error = "";
249
- @error = params['captures'].first.inspect if "#{$mode}".strip == 'development'
250
- end
251
-
252
- post '/v1/send' do
253
- app = params[:app]
254
- message = CGI::escape(params[:message] || "")
255
- pid = "#{Time.now.to_i}"
256
- # begin
257
- # url = URI.parse("http://localhost:#{$port}/v1/apps/#{app}/push")
258
- # post_args1 = { :alert => "#{message}".encode('UTF-8'), :pid => "#{pid}" }
259
- # Net::HTTP.post_form(url, post_args1)
260
- # rescue =>err
261
- # puts "#{err.class} ##{err}"
262
- # end
263
- system "curl http://localhost:#{$port}/v1/apps/#{app}/push/#{message}/#{pid}"
264
- redirect '/v1/admin/push' if (params[:app] and params[:message])
265
- end
266
-
267
- get "/v1/admin/:db" do
268
- protected!
269
- db = params[:db] || 'token'
270
- page = 1
271
- page = params[:page].to_i if params[:page]
272
- if (db == 'token') then
273
- @o = []
274
- $apps.each_with_index { |app, index|
275
- @o << Token.where(:app => app).order(:id).reverse.paginate(page, 20)
276
- }
277
- erb :token
278
- elsif (db == 'push') then
279
- @p = []
280
- $apps.each_with_index { |app, index|
281
- @p << Push.where(:app => app).order(:id).reverse.paginate(page, 20)
282
- }
283
- erb :push
284
- else
285
- erb :not_found
286
- end
287
- end
288
-
289
- $apps.each { |app|
290
-
291
- ## register token api
292
- get "/v1/apps/#{app}/:token" do
293
- if (("#{params[:token]}".length == 64) and iOS? and checkFlood?(request) ) then
294
- puts "[#{params[:token]}] was added to '#{app}'" if "#{$mode}".strip == 'development'
295
- o = Token.first(:app => app, :token => params[:token])
296
- unless o
297
- Token.insert(
298
- :app => app,
299
- :token => params[:token],
300
- :created_at => Time.now
301
- )
302
- end
303
- end
304
- end
305
-
306
- ## http POST method push api
307
- post "/v1/apps/#{app}/push" do
308
- protected! unless request.host == 'localhost'
309
- message = CGI::unescape(params[:alert] || "")[0..107]
310
- badge = 1
311
- puts "params[:badge] = [#{params[:badge]}]"
312
- badge = params[:badge].to_i if params[:badge] and params[:badge] != ''
313
- sound = CGI::unescape(params[:sound] || "")
314
- extra = CGI::unescape(params[:extra] || "")
315
-
316
- puts "#{badge} : #{message} extra: #{extra}" if "#{$mode}".strip == 'development'
317
- pid = params[:pid]
318
-
319
- puts "'#{message}' was sent to (#{app}) with pid: [#{pid}], badge:#{badge} , sound: #{sound}, extra:#{extra}" if "#{$mode}".strip == 'development'
320
-
321
- @tokens = Token.where(:app => "#{app}")
322
- @exist = Push.first(:pid => "#{pid}", :app => "#{app}")
323
-
324
- unless @exist
325
-
326
- Push.insert(:pid => pid, :message => message, :created_at => Time.now, :app => "#{app}" )
327
-
328
- openSSLContext = $certkey["#{app}"]
329
- # Connect to port 2195 on the server.
330
- sock = nil
331
- if $mode == 'production' then
332
- sock = TCPSocket.new('gateway.push.apple.com', 2195)
333
- else
334
- sock = TCPSocket.new('gateway.sandbox.push.apple.com', 2195)
335
- end
336
- # do our SSL handshaking
337
- sslSocket = OpenSSL::SSL::SSLSocket.new(sock, openSSLContext)
338
- sslSocket.connect
339
-
340
- # write our packet to the stream
341
- @tokens.each do |o|
342
- tokenText = o[:token]
343
- # pack the token to convert the ascii representation back to binary
344
- tokenData = [tokenText].pack('H*')
345
- # construct the payload
346
- po = {:aps => {:alert => "#{message}", :badge => badge, :sound => "#{sound}"}, :extra => "#{extra}"}
347
- payload = ActiveSupport::JSON.encode(po)
348
- # construct the packet
349
- packet = [0, 0, 32, tokenData, 0, payload.length, payload].pack("ccca*cca*")
350
- # read our certificate and set up our SSL context
351
- sslSocket.write(packet)
352
- end
353
- # cleanup
354
- sslSocket.close
355
- sock.close
356
- end
357
- end
358
-
359
- ## http GET method push api
360
- get "/v1/apps/#{app}/push/:message/:pid" do
361
- protected! unless request.host == 'localhost'
362
- message = CGI::unescape(params[:message])
363
- puts message if "#{$mode}".strip == 'development'
364
- pid = params[:pid]
365
-
366
- puts "'#{message}' was sent to (#{app}) with pid: [#{pid}]" if "#{$mode}".strip == 'development'
367
-
368
- @tokens = Token.where(:app => "#{app}")
369
- @exist = Push.first(:pid => "#{pid}", :app => "#{app}")
370
-
371
- unless @exist
372
-
373
- Push.insert(:pid => pid, :message => message, :created_at => Time.now, :app => "#{app}" )
374
-
375
- openSSLContext = $certkey["#{app}"]
376
- # Connect to port 2195 on the server.
377
- sock = nil
378
- if $mode == 'production' then
379
- sock = TCPSocket.new('gateway.push.apple.com', 2195)
380
- else
381
- sock = TCPSocket.new('gateway.sandbox.push.apple.com', 2195)
382
- end
383
- # do our SSL handshaking
384
- sslSocket = OpenSSL::SSL::SSLSocket.new(sock, openSSLContext)
385
- sslSocket.connect
386
-
387
- # write our packet to the stream
388
- @tokens.each do |o|
389
- tokenText = o[:token]
390
- # pack the token to convert the ascii representation back to binary
391
- tokenData = [tokenText].pack('H*')
392
- # construct the payload
393
- po = {:aps => {:alert => "#{message}", :badge => 1}}
394
- payload = ActiveSupport::JSON.encode(po)
395
- # construct the packet
396
- packet = [0, 0, 32, tokenData, 0, payload.length, payload].pack("ccca*cca*")
397
- # read our certificate and set up our SSL context
398
- sslSocket.write(packet)
399
- end
400
- # cleanup
401
- sslSocket.close
402
- sock.close
403
- end
404
- end
405
- }
406
- end
3
+ require 'ass/conf'
4
+ require 'ass/app'