大家都知道iOS的企业证书开发的APP,证书都是一年有效期,满一年得新建证书重新打包,否则无法继续使用。

我们一个企业账号下有几十个APP,一个个去看也很麻烦~~搞个监控呗!!!

写个脚本放Jenkins上定时跑就行,跑完发布邮件:

1.邮件包含信息:APP名称,APP相关的bundle id、证书名称、签名时间、团队id,过期时间,以及剩余有效的月数。

common_mail.py: 发布邮件,邮件发送网上多,自己找,不累述

copy_ipa_monitor.py: 把打好的ipa复制到指定的目录,这个目录给监控的扫描用

date_month.py: 专门计算月份差,Python没有直接计算月份差的模块,自己写,考虑下各种条件计算

ipa_monitor.py: 获取ipa的有效时间以及ipa包里描述文件里的有效时间

ipa_monitor_html.py: 生成邮件发送的html模版

贴代码:

  1 ## ipa_monitor.py
2 # coding = utf-8
3 # 读取配置证书
4
5 import os
6 import time
7 import shutil
8 import datetime
9 from pkg_common.cmd import common_run_cmd as cmd
10 from pkg_common.handle_file import find_file as find
11 from pkg_common.ipa_monitor import common_mail as mail
12 from pkg_common.ipa_monitor import ipa_monitor_html as html
13
14
15 to_find_path = '/Users/Work/package/ipa_monitor'
16
17
18 # 获取证书时间一些命令
19 codesign_cmd = 'codesign -d --extract-certificates Payload/*.app'
20 openssl_cmd = 'openssl x509 -inform DER -in codesign0 -noout -nameopt -oneline -dates'
21 codesign_get_cmd = 'codesign -dv --verbose=4 Payload/*.app'
22 mobile_provision_cmd = 'more Payload/Runner.app/embedded.mobileprovision'
23
24
25 def get_ipa_time():
26 f, f_l = find.find_file("'*.ipa'", to_find_path)
27 all_dic = []
28 for i in f_l:
29 dic = {}
30 dir_name = os.path.dirname(i)
31 app_name = dir_name.split('/')[-1]
32 dic['app_name'] = app_name
33 base_name = os.path.basename(i)
34 un_zip_cmd = 'unzip -q %s' % base_name
35 # 解压ipa文件
36 cmd.run_cmd(un_zip_cmd, dir_name)
37 time.sleep(2)
38 cmd.run_commands(codesign_cmd, dir_name)
39 time.sleep(2)
40 not_time = cmd.run_commands(openssl_cmd, dir_name)[1]
41 not_after, not_stamp = deal_gmt(not_time.split('\n')[1].split('=')[1])
42 f, f_l = find.find_file("'*.mobileprovision'", dir_name)
43 ipa_no_time = ''
44 ipa_no_stamp = 0
45 # 获取描述文件里的过期时间,这里解码格式一定要用ISO-8859-1
46 with open(f_l[0], 'r', encoding='ISO-8859-1') as f_w:
47 lines = f_w.readlines()
48 for index, l in enumerate(lines):
49 if 'ExpirationDate' in l:
50 ipa_no_time = lines[index+1].split('>')[1].split('<')[0]
51 ipa_no_time, ipa_no_stamp = deal_utc(ipa_no_time)
52 break
53 if not_stamp <= ipa_no_stamp:
54 expired_time = not_after
55 else:
56 expired_time = ipa_no_time
57 dic['expired_time'] = expired_time
58 pro_info = cmd.run_commands(codesign_get_cmd, dir_name)[1].split('\n')
59 delete_file(dir_name)
60
61 for x in pro_info:
62 if 'Identifier' == x.split('=')[0]:
63 dic['Identifier'] = x.split('=')[1]
64 if 'Authority' in x:
65 if 'Authority' not in dic:
66 dic['Authority'] = x.split('=')[1]
67 if 'Signed Time' in x:
68 dic['Signed_time'] = x.split('=')[1]
69 if 'TeamIdentifier' in x:
70 dic['TeamIdentifier'] = x.split('=')[1]
71 all_dic.append(dic)
72 return all_dic
73
74
75 def deal_gmt(gmt_time):
76 """
77 GMT时间转换
78 :param gmt_time:
79 :return:
80 """
81 gmt_format = '%b %d %H:%M:%S %Y GMT'
82 # GMT时间与北京时间相差8小时
83 sta_time = datetime.datetime.strptime(gmt_time, gmt_format) + datetime.timedelta(hours=8)
84 time_array = time.strptime(str(sta_time), "%Y-%m-%d %H:%M:%S")
85 time_stamp = int(time.mktime(time_array))
86 return sta_time, time_stamp
87
88
89 def deal_utc(utc_time):
90 utc_format = "%Y-%m-%dT%H:%M:%SZ"
91 sta_time = datetime.datetime.strptime(utc_time, utc_format) + datetime.timedelta(hours=8)
92 time_array = time.strptime(str(sta_time), "%Y-%m-%d %H:%M:%S")
93 time_stamp = int(time.mktime(time_array))
94 return sta_time, time_stamp
95
96
97 def delete_file(dir_name):
98 """
99 删除多余文件
100 :param dir_name:
101 :return:
102 """
103 os.remove(dir_name + '/codesign0')
104 os.remove(dir_name + '/codesign1')
105 os.remove(dir_name + '/codesign2')
106 shutil.rmtree(dir_name + '/Payload')
107
108
109 if __name__ == '__main__':
110 ipa_info = get_ipa_time()
111 subject, html = html.deal_html(ipa_info)
112 try:
113 if mail.cs_mail_send(subject, html, 'c'):
114 print('Send success')
115 else:
116 print('Send failure')
117 except Exception as e:
118 raise e
119
## date_month.py

import datetime
import calendar as c def cal_months(start_date, end_date): # 计算两个日期相隔月差
try:
same_month_date = datetime.date(end_date.year, end_date.month, start_date.day)
except Exception as e:
print(e)
same_month_date = datetime.date(end_date.year, end_date.month, c.monthrange(end_date.year, end_date.month)[1])
decimal_month = 0.0
if same_month_date > end_date:
try:
pre_date = datetime.date(end_date.year, end_date.month - 1, start_date.day)
except Exception as e:
print(e)
pre_date = datetime.date(end_date.year, end_date.month - 1, c.monthrange(end_date.year, end_date.month - 1)[1])
curr_month_days = (same_month_date - pre_date).days
hold_months = (pre_date.year - start_date.year) * 12 + pre_date.month - start_date.month
decimal_month = round((end_date - pre_date).days / curr_month_days, 1) elif same_month_date < end_date:
try:
next_month_date = datetime.date(end_date.year, end_date.month + 1, start_date.day)
except Exception as e:
print(e)
next_month_date = datetime.date(end_date.year, end_date.month + 1, c.monthrange(end_date.year, end_date.month + 1)[1])
curr_month_days = (next_month_date - same_month_date).days
hold_months = (same_month_date.year - start_date.year) * 12 + same_month_date.month - start_date.month
decimal_month = round((end_date - same_month_date).days / curr_month_days, 1) else:
hold_months = (end_date.year - start_date.year) * 12 + end_date.month - start_date.month return hold_months + decimal_month
## ipa_monitor_html.py
# coding = utf-8
# ipa过期时间监控 import datetime
from pkg_common.ipa_monitor import date_month as dm # 处理html
def deal_html(data):
tl = deal_tl(data)
subject = '企业证书iOS应用过期时间监控'
html = """
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>企业证书iOS应用过期时间监控</title>
<body>
<div id="container">
<center>
<strong>汇总时间: """ + str(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + """</strong>
<p><strong></strong></p>
<div id="content">
<table border="1" cellpadding="2" style="border-collapse:collapse;margin-top:10px">
<tr>
<td colspan="4" align="center" height="35px"><font size="4"><strong>只针对企业证书打包的应用</strong>[<font color="red">有效期小于3月的红色加粗显示</font>]</font></td>
</tr>
<tr height="28px" bgcolor="#f0f8ff">
<td width="120" align="center"><font size="3"><strong>应用名称</strong></font></td>
<td width="520" align="center"><font size="3"><strong>APP参数</strong></font></td>
<td width="180" align="center"><font size="3"><strong>过期时间</strong></font></td>
<td width="80" align="center"><font size="3"><strong>剩余月数</strong></font></td>
</tr>
""" + tl + """
</tr>
</table>
<p><font size="3" ><center>--------------------<strong><a href="http://chandao.thecover.cn/">汇总数据源于测试监控系统</a></strong>--------------------</center></font>
</center>
</div>
</div>
</div>
</body>
</html>
"""
return subject, html def deal_tl(data): tl_a = ''
for i in data: dt1 = i['expired_time'].date()
dt2 = datetime.date.today()
dt = dm.cal_months(dt2, dt1) a = """
<tr>
<td rowspan="4" align="center"> %s </td>
<td align="left"> Identifier:%s</td>
<td rowspan="4" align="center"> %s</td>
""" % (i['app_name'], i['Identifier'], i['expired_time']) if dt > 3:
b = """ <td rowspan="4" align="center"> %s</td> """ % dt
else:
b = """ <td rowspan="4" align="center"> <strong><font color="red"> %s </font></strong></td> """ % dt c = """
</tr>
<tr>
<td align="left"> Authority:%s</td>
</tr>
<tr>
<td align="left"> Signed_time:%s </td>
</tr>
<tr>
<td align="left"> TeamIdentifier:%s </td>
</tr>
<tr>
<td colspan="4" align="center" height="0px" bgcolor="#a9a9a9"><font size="4"> </td>
</tr>
""" % (i['Authority'], i['Signed_time'], i['TeamIdentifier']) tl_a = tl_a + a + b + c return tl_a

其他py文件很简单,就不贴了,若遇到问题,可留言交流~~

iOS企业证书开发的APP证书过期时间监控的更多相关文章

  1. 安卓和ios的app证书过期的相关问题汇总

    一,ios的APP的发布流程请见:ios的APP的发布流程 http://www.jianshu.com/p/b1b77d804254 这篇文章写得很好很全面 二,app证书过期了怎么办: IOS的情 ...

  2. XE6 & IOS开发之免证书真机调试(1):颁发属于自己的App签名证书(有图有真相)

    网上能找到的关于Delphi XE系列的移动开发的相关文章甚少,本文尽量以详细的图文内容.傻瓜式的表达来告诉你想要的答案. 原创作品,请尊重作者劳动成果,转载请注明出处!!! 1.自己给自己颁发证书, ...

  3. IOS开发创建开发证书及发布App应用(二)——创建证书

    2. 创建证书 证书分为两种,一种是开发者证书,主要是用来真机调试的 另一种就是发布证书,就是用来发布应用的, 最好是两种都要下载,不然编译时候可能报错,我猜想可能苹果怕你没用真机调试 创建证书分为两 ...

  4. IOS开发创建开发证书及发布App应用(一)——流程说明

    之前在自己做的博客网站上面发布了这个系列的文章,当时还是不错的,帮助了很多跟我一样的新手朋友,不过由于服务器出现问题,丢失了一年了,现在终于找到了,所以发到博客园给大家共享一下,也是为我自己做个参考 ...

  5. 【iOS开发】企业版证书($299)In-House方式发布指南 (转)

    一.明确几个概念 1.企业版IDP:即iOS Development Enterprise Program.注意是$299/Year那种,并不是$99/Year的那种. 2.In House:是只企业 ...

  6. 关于iOS开发的各种证书

    关于iOS开发的各种证书 最近在接推送服务的时候,被各种证书弄得不亦晕乎,这里记录一下一些基本的证书作用: 1. App IDs appID分明确的和通配的两种,如果要使用推送功能,只能用明确的. 2 ...

  7. iOS开发-- 开发环境,证书和授权文件

    一.成员介绍 1.    Certification(证书)证书是对电脑开发资格的认证,每个开发者帐号有一套,分为两种:1)    Developer Certification(开发证书)安装在电脑 ...

  8. IOS 开发环境,证书和授权文件等详解

    (转自:http://blog.csdn.net/gtncwy/article/details/8617788) 一.成员介绍1.    Certification(证书)证书是对电脑开发资格的认证, ...

  9. ios 企业证书 ipa 重新签名发布

    提示:暂时不能用了,企业证书滥用 ios 企业证书 ipa 重新签名发布 1. 应用场景 当前有一个 未用企业证书签名的 ipa 文件,默认是不可以直接安装到设备上的:我们需要用企业版证书签名: 当前 ...

  10. iOS开发HTTPS实现之信任SSL证书和自签名证书

    iOS开发HTTPS实现之信任SSL证书和自签名证书 转自:http://www.jianshu.com/p/6b9c8bd5005a/comments/5539345 (收录一下供自己学习用的) 字 ...

随机推荐

  1. JVM(一)-内存结构

    我们都知道,我们写的Java程序需要先经过编译,生成了.class文件(字节码文件).然而,计算机并不能直接解释.class文件里面的内容,这时候就需要一个能加载.解释.class文件并且能按.cla ...

  2. translate speaker 翻译朗读者API - vscode 插件推荐 单词发音

    translate speaker 翻译朗读者API - vscode 插件推荐 单词发音 有个小bug,就是发音发两次,改个配置就好了. "translateSpeaker.mode&qu ...

  3. 基于泰凌微TLSR8355的无线灯光智能控制系统解决方案调试总结

    前记  随着新技术的不断发展,在灯控市场.使用无线和传感器技术让灯的利用变得更加环保和智能是一个相对时尚的选择.最近跟几个客户做了一些此类的产品.发掘了一些有趣的功能和应用.这里做一个梳理. 特色梳理 ...

  4. AWS API Gateway IP WhileList

    首先创建个API,然后进入API配置,点击左边的资源配置,加入以下配置: { "Version": "2012-10-17", "Statement& ...

  5. 海量数据去重的Hash与BloomFilter

    今天我们谈论一下散列表,我之前的两个博文写的都是关于平衡二叉树的 平衡二叉树 增删改查时间复杂度为log2n 平衡的目的是增删改以后,保证下次搜索能稳定排除一半的数据: 总结:通过比较保证有序,通过每 ...

  6. UE像素流送是什么?像素流推流原理介绍

    游戏开发者通常在运行游戏逻辑时会将游戏渲染到屏幕的同一台设备上来运行虚幻引擎应用,多人联网游戏可能会在应用程序的多个实例之间分发部分游戏逻辑,但每个单独的实例仍然会为自己的玩家在本地渲染游戏.即使是使 ...

  7. [.NET项目实战] Elsa开源工作流组件应用(二):内核解读

    @ 目录 定义 变量 内存寄存器类 寄存器中的存储区块类 变量到存储的映射类 上下文对象 活动上下文(ActivityExecutionContext) 工作流执行上下文(WorkflowExecut ...

  8. vivado的非嵌入ILA的使用

    vivado非嵌入ILA的使用 1.实验原理 前面在vivado中联合vitis设计时接触过ila,那个时候采用的方法是直接调用IP核在原理图中连接.这个方法简单直接,可以将自己所需的测量信号转移到I ...

  9. KingbaseES V8R6集群运维案例之---访问系统表unrecognized token- false故障

    KingbaseES V8R6集群运维案例之---访问系统表'unrecognized token: "false"'故障 案例说明: KingbaseES V8R6集群在升级补丁 ...

  10. java实战字符串4:寻找最长的元音子串的长度

    题目描述 定义:当一个字符串只有元音字母(aeiouAEIOU)组成,称为元音字符串.现给定一个字符串,请找出其中最长的元音字符子串,并返回其长度:如果找不到,则返回0. 子串:字符串中任意个连续的字 ...