├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── add_domain.php ├── auth.php ├── cf.class.php ├── config.php ├── delete_domain.php ├── domains.php ├── edit_record.php ├── footer.php ├── header.php ├── index.php └── manage_domain.php /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://blog.yuzu.im/donate'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | config.php -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 131 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CFPMP 2 | Cloudflare Partner Management Panel 3 | 4 | 打开config.php,根据里面的注释进行设置后即可使用 5 | 6 | ## 功能 7 | * CNAME接入 8 | * reCAPTCHA 9 | * 设置回源地址为IP(基于sslip.io)(默认关闭此功能) 10 | * 通过 TXT 记录验证域名是否受用户控制 11 | 12 | 可用实例:[https://cf.yuzu.im/](https://cf.yuzu.im/) 13 | -------------------------------------------------------------------------------- /add_domain.php: -------------------------------------------------------------------------------- 1 | is_login(); 5 | 6 | function msg($s) 7 | { 8 | $_SESSION["msg"] = $s; 9 | header("Location: domains.php"); 10 | exit(0); 11 | } 12 | 13 | if (empty($_POST["domain"])) { 14 | msg("域名不能为空"); 15 | } 16 | 17 | if (Enable_TXT_Verification){ 18 | if (!$cloudflare->check_txt_record($_POST["domain"])){ 19 | msg("TXT 记录验证失败"); 20 | } 21 | } 22 | 23 | $r = $cloudflare->zone_set($_POST["domain"], $_POST["domain"], "www:" . $_POST["domain"]); 24 | 25 | if ($r["result"] == "success") { 26 | msg("添加成功"); 27 | } else { 28 | if (empty($r["msg"])) { 29 | msg("请刷新本页面以确认域名是否添加成功"); 30 | } else { 31 | msg("添加失败:" . $r["msg"]); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /auth.php: -------------------------------------------------------------------------------- 1 | reCAPTCHA($_POST["g-recaptcha-response"]))) { 15 | msg("请完成验证码"); 16 | } 17 | } else { 18 | msg("请完成验证码"); 19 | } 20 | } 21 | 22 | if ((!empty($_POST["email"])) && (!empty($_POST["password"]))) { 23 | $r = $cloudflare->login($_POST["email"], $_POST["password"]); 24 | if ($r["result"] == "success") { 25 | $_SESSION["user_key"] = $r["response"]["user_key"]; 26 | $_SESSION["email"] = $r["response"]["cloudflare_email"]; 27 | $_SESSION["api_key"] = $r["response"]["user_api_key"]; 28 | //if (Enable_TXT_Verification) $_SESSION["txt_verification"] = password_hash(Random_String.$_SESSION["email"],PASSWORD_BCRYPT ); 29 | header("Location: domains.php"); 30 | } else { 31 | msg("失败:" . $r["msg"]); 32 | } 33 | } else { 34 | msg("用户名和密码不能为空"); 35 | } 36 | -------------------------------------------------------------------------------- /cf.class.php: -------------------------------------------------------------------------------- 1 | "CNAME", 138 | "name" => $name, 139 | "content" => self::add_suffix_for_ip($content), 140 | "ttl" => 1, 141 | "proxied" => true 142 | ]); 143 | } 144 | 145 | public function edit_record($zone_id, $record_id, $name, $content){ 146 | return self::user_api_post("https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records/$record_id", [ 147 | 'type' => 'CNAME', 148 | 'name' => $name, 149 | 'content' => self::add_suffix_for_ip($content), 150 | 'ttl' => 1, 151 | "proxied" => true 152 | ], "PUT"); 153 | } 154 | 155 | public function delete_record($zone_id, $record_id){ 156 | $data = self::user_api_post("https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records/$record_id", [], "DELETE"); 157 | $data['result']['id']==$record_id ? $data['success'] = true : $data['success'] = false; 158 | return $data; 159 | } 160 | 161 | public function add_suffix_for_ip($content){ 162 | if (Enable_A_Record&&(filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))){ 163 | return $content.".sslip.io"; 164 | }else{ 165 | return $content; 166 | } 167 | } 168 | 169 | public function reCAPTCHA($response) 170 | { 171 | $url = "https://www.recaptcha.net/recaptcha/api/siteverify"; 172 | $data = array( 173 | "secret" => reCAPTCHA_Secret, 174 | "response" => $response 175 | ); 176 | $ch = curl_init(); 177 | curl_setopt($ch, CURLOPT_URL, $url); 178 | curl_setopt($ch, CURLOPT_POSTFIELDS, $data); 179 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 180 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); 181 | $r = curl_exec($ch); 182 | curl_close($ch); 183 | $re = json_decode($r, true); 184 | if (!empty($re["success"])) { 185 | if ($re["success"] == "true") { 186 | return true; 187 | } else { 188 | return false; 189 | } 190 | } else { 191 | return false; 192 | } 193 | } 194 | 195 | public function check_txt_record($domain){ 196 | foreach(dns_get_record("cfpmp.".$domain, DNS_TXT) as $v){ 197 | if (password_verify(Random_String.$_SESSION["email"], $v["txt"])) return true; 198 | } 199 | return false; 200 | } 201 | } 202 | 203 | $cloudflare = new CF(); -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | is_login(); 5 | 6 | function msg($s) 7 | { 8 | $_SESSION["msg"] = $s; 9 | header("Location: domains.php"); 10 | exit(0); 11 | } 12 | 13 | if (empty($_POST["domain"])) { 14 | msg("域名不能为空"); 15 | } 16 | 17 | $r = $cloudflare->zone_delete($_POST["domain"]); 18 | 19 | if ($r["result"] == "success") { 20 | msg("删除成功"); 21 | } else { 22 | msg("删除失败:" . $r["msg"]); 23 | } -------------------------------------------------------------------------------- /domains.php: -------------------------------------------------------------------------------- 1 | is_login(); 6 | 7 | $r = $cloudflare->user_lookup(); 8 | 9 | include_once("header.php"); 10 | 11 | $output = ''; 12 | ?> 13 | 14 |
15 |
16 |
17 | 18 |
19 |
20 | Cloudflare Partners : 21 | 22 | > 23 | 域名管理 24 |
25 |
26 |
27 |
28 | . 29 | 登出 30 |
31 |
32 | 33 | 34 |
35 |
36 |
37 | 40 | 41 | 42 |
43 |
44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 58 | 59 | 60 | 61 | 62 | '; 63 | } 64 | echo $output; 65 | ?> 66 | 67 |
域名
' . $value . '管理删除
68 |
69 | 70 | 71 |

查询失败: 72 | 73 | 74 | 75 |

无域名,赶紧添加一个吧!

76 | 77 | 78 |
79 |
80 |
81 | 82 |
83 |
84 |
85 | 86 |
87 |
添加域名
88 |
89 |
90 |
91 | 92 | 93 |
94 | 95 |

96 | 请在此域名添加名称为 cfpmp 的 TXT 记录此记录可在验证完毕后删除 97 |

98 |

99 | 因 Cloudflare Host API 更新,可能无法添加新域名。 100 |

101 | 102 |
103 |
104 | 105 | 106 |
107 |
108 |
109 | 110 |
111 |
删除域名
112 |
113 |
114 | 你确定要删除域名 115 | 116 | 117 | 吗? 118 |
119 |
120 | 121 | 122 |
123 |
124 |
125 | 126 |
127 |
128 | 133 |
134 |
135 | 136 |
137 |
138 | 139 | 149 | 150 | 153 | var inst = new mdui.Dialog("#msg_dialog",{ 154 | history: false 155 | }); 156 | inst.open(); 157 | 158 | SCRIPT; 159 | if (!empty($_SESSION["msg"])) { 160 | echo $msg_script; 161 | unset($_SESSION["msg"]); 162 | } 163 | 164 | include_once("footer.php"); 165 | ?> 166 | -------------------------------------------------------------------------------- /edit_record.php: -------------------------------------------------------------------------------- 1 | is_login(); 5 | 6 | function msg($s) 7 | { 8 | $_SESSION["mng_msg"] = $s; 9 | header("Location: manage_domain.php?domain=" . $_POST["domain"]); 10 | exit(0); 11 | } 12 | 13 | if (empty($_POST["zone_id"])) { 14 | $_SESSION["msg"] = "域名不能为空"; 15 | header("Location: domains.php"); 16 | exit(0); 17 | } 18 | 19 | if (empty($_POST["action"])) { 20 | msg("操作不存在"); 21 | } 22 | 23 | if (empty($_POST["record"])&&empty($_POST["record_id"])) { 24 | msg("记录不能为空"); 25 | } 26 | 27 | $re = $cloudflare->zone_lookup($_POST["domain"]); 28 | if ($re["result"] != "success") { 29 | msg("操作失败:" . $re["msg"]); 30 | } 31 | if ($re["response"]["zone_exists"] != true) { 32 | msg("该域名未在Cloudflare接入"); 33 | } 34 | if ($re["response"]["zone_hosted"] != true) { 35 | msg("该域名未在" . SITE_NAME . "接入"); 36 | } 37 | 38 | if ($_POST["action"] == "delete") { 39 | if (!empty($_POST["record_id"])) { 40 | $result = $cloudflare->delete_record($_POST["zone_id"], $_POST["record_id"]); 41 | if ($result["success"]) { 42 | msg("删除成功"); 43 | } else { 44 | msg("删除失败"); 45 | } 46 | } else { 47 | msg("缺少参数"); 48 | } 49 | } elseif ($_POST["action"] == "edit") { 50 | if (!empty($_POST["record_id"])&&!empty($_POST["value"])&&!empty($_POST["record"])) { 51 | $result = $cloudflare->edit_record($_POST["zone_id"], $_POST["record_id"], $_POST["record"], $_POST["value"]); 52 | if ($result["success"]) { 53 | msg("更新成功"); 54 | } else { 55 | msg("更新失败:" . $result["errors"][0]["message"]); 56 | } 57 | } else { 58 | msg("缺少参数"); 59 | } 60 | } elseif ($_POST["action"] == "add") { 61 | if (!empty($_POST["value"])&&!empty($_POST["record"])) { 62 | $result = $cloudflare->add_record($_POST["zone_id"], $_POST["record"], $_POST["value"]); 63 | if ($result["success"]) { 64 | msg("添加成功"); 65 | } else { 66 | msg("添加失败:" . $result["errors"][0]["message"]); 67 | } 68 | } else { 69 | msg("缺少参数"); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /footer.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | Supported by 5 | 6 | 7 | . 8 |
9 | 10 | CFPMP v0.3.2 | Help 11 |
12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <?php echo SITE_NAME; ?> - Cloudflare Partners 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | logout(); 6 | 7 | include_once("header.php"); 8 | ?> 9 | 10 |
11 |
12 |
13 | 14 |
15 |
16 | Cloudflare Partners : 17 | 18 |
19 |
20 |
21 |
22 | 23 |
24 |
25 |
26 |
27 | 28 |
29 |

登入 30 | 31 |

32 |
33 |
34 | 35 | 36 |
37 | 38 |
39 | 40 | 41 |
42 | 43 | 44 |
45 | 46 | 47 |
48 |
49 | 51 |
52 |
53 | 54 |
55 |
56 |
57 |
58 | 59 |
60 |
61 |
62 | 63 |
64 |
65 | 68 |
69 |
70 | 71 |
72 |
73 | 74 | 77 | var inst = new mdui.Dialog("#error",{ 78 | history: false 79 | }); 80 | inst.open(); 81 | 82 | SCRIPT; 83 | if (!empty($_SESSION["login_msg"])) { 84 | echo $error; 85 | unset($_SESSION["login_msg"]); 86 | } 87 | include_once("footer.php"); 88 | ?> -------------------------------------------------------------------------------- /manage_domain.php: -------------------------------------------------------------------------------- 1 | is_login(); 6 | 7 | function msg($s) 8 | { 9 | $_SESSION["msg"] = $s; 10 | header("Location: domains.php"); 11 | exit(0); 12 | } 13 | 14 | if (empty($_GET["domain"])) { 15 | msg("域名不能为空"); 16 | } 17 | 18 | $re = $cloudflare->zone_lookup($_GET["domain"]); 19 | if ($re["result"] != "success") { 20 | msg("查询失败:" . $re["msg"]); 21 | } 22 | if ($re["response"]["zone_exists"] != true) { 23 | msg("该域名未在Cloudflare接入"); 24 | } 25 | if ($re["response"]["zone_hosted"] != true) { 26 | msg("该域名未在" . SITE_NAME . "接入"); 27 | } 28 | 29 | $r = $cloudflare->get_proxied_records($_GET["domain"]); 30 | $zone_id = $cloudflare->get_zone_id($_GET["domain"]); 31 | 32 | if (!$r["success"]) { 33 | msg("查询失败:" . $r["errors"][0]["message"]); 34 | } 35 | 36 | include_once("header.php"); 37 | ?> 38 | 39 |
40 |
41 |
42 | 43 |
44 |
45 | Cloudflare Partners : 46 | 47 | > 48 | 域名管理 > 49 | 50 | 51 | 52 |
53 |
54 |
55 |
56 | . 57 | 登出 58 |
59 |
60 | 61 |
62 |
63 |
64 | 65 |
66 | 67 | 68 | 69 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | $data) { 83 | if ((Enable_A_Record) && (filter_var(str_replace('.sslip.io', '', $data['content']), FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))) { 84 | $data['content'] = str_replace('.sslip.io', '', $data['content']); 85 | } 86 | echo "" . 87 | '' . 94 | "'; 97 | } 98 | ?> 99 | 100 |
70 | 74 | 记录CNAME记录回源地址
" . substr($data['name'],0,strlen($data['name'])-strlen($data['zone_name'])-1) . ""; 95 | echo $data['name'].'.cdn.cloudflare.net'; 96 | echo '' . $data['content'] . '
101 |
102 |

103 | 注 104 | (1):必须设置一个www记录,否则会自动设置一个回源地址为www记录。本记录可不在DNS服务商配置 105 |

106 | 107 |

108 | 注 (3):回源地址以CNAME形式填写,暂时不支持A记录和AAAA记录 109 |

110 | 111 |
112 |
113 |
114 | 115 |
116 |
117 |
118 | 119 |
120 |
删除记录
121 |
122 |
123 | 124 | 125 | " name="domain"/> 126 | 127 | 你确定要删除记录 128 | 129 | 130 | 吗? 131 |
132 |
133 | 134 | 135 |
136 |
137 |
138 | 139 |
140 |
修改记录
141 |
142 |
143 | 144 | 145 | " name="domain"/> 146 | 147 |
148 | 149 | 150 |
151 |
152 | 153 | 154 |
155 |
156 |
157 | 158 | 159 |
160 |
161 |
162 | 163 | 201 | 202 |
203 |
204 | 209 |
210 |
211 | 212 |
213 |
214 | 215 | 218 | var inst = new mdui.Dialog("#msg_dialog",{ 219 | history: false 220 | }); 221 | inst.open(); 222 | 223 | SCRIPT; 224 | if (!empty($_SESSION["mng_msg"])) { 225 | echo $msg_script; 226 | unset($_SESSION["mng_msg"]); 227 | } 228 | 229 | include_once("footer.php"); 230 | ?> 231 | --------------------------------------------------------------------------------