請求の確認

This commit is contained in:
2026-05-04 14:15:29 +09:00
parent 2570955b4e
commit fc777da399
17 changed files with 398 additions and 390 deletions

1
.gitignore vendored
View File

@@ -8,3 +8,4 @@ public/static/user
!public/static/user/.kara !public/static/user/.kara
config/config.php config/config.php
public/static/*.pem public/static/*.pem
.vscode

View File

@@ -96,6 +96,9 @@ if (ATOM_ENABLED) {
if (OPENPROVIDER_ENABLED) { if (OPENPROVIDER_ENABLED) {
$routes[] = Route::add('GET', 'openprovider', Op::class.'@index'); $routes[] = Route::add('GET', 'openprovider', Op::class.'@index');
$routes[] = Route::add('GET', 'openprovider/listinvoices', Op::class.'@opListInvoices');
$routes[] = Route::add('GET', 'openprovider/listpayments', Op::class.'@opListPayments');
$routes[] = Route::add('GET', 'openprovider/listtransactions', Op::class.'@opListTransactions');
$routes[] = Route::add('GET', 'openprovider/listcustomers', Op::class.'@opListCustomers'); $routes[] = Route::add('GET', 'openprovider/listcustomers', Op::class.'@opListCustomers');
$routes[] = Route::add('GET', 'openprovider/createcustomer', Op::class.'@opCreateCustomer'); $routes[] = Route::add('GET', 'openprovider/createcustomer', Op::class.'@opCreateCustomer');
$routes[] = Route::add('GET', 'openprovider/deletecustomer/{handle}', Op::class.'@opDeleteCustomer'); $routes[] = Route::add('GET', 'openprovider/deletecustomer/{handle}', Op::class.'@opDeleteCustomer');

View File

@@ -37,6 +37,8 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
namespace Site\Controller; namespace Site\Controller;
use Roles;
class BlogPost { class BlogPost {
/** /**
* ブログ投稿を取得する * ブログ投稿を取得する
@@ -46,9 +48,9 @@ class BlogPost {
public function getPosts(string $section, ?\stdClass $user = null): array { public function getPosts(string $section, ?\stdClass $user = null): array {
$path = ROOT.$section; $path = ROOT.$section;
$posts = []; $posts = [];
$isMember = $user !== NULL && $user->role !== \Roles::BANNED; $isMember = $user !== NULL && $user->role !== Roles::BANNED;
$isPaywall = $user !== NULL && $user->role >= \Roles::SUBSCRIBER; $isPaywall = $user !== NULL && $user->role >= Roles::SUBSCRIBER;
$isStaff = $user !== NULL && $user->role & (\Roles::ADMIN | \Roles::STAFF); $isStaff = $user !== NULL && $user->role & (Roles::ADMIN | Roles::STAFF);
if (!is_dir($path)) return $posts; if (!is_dir($path)) return $posts;
$files = glob($path.'/*.md'); $files = glob($path.'/*.md');

View File

@@ -40,6 +40,7 @@ namespace Site\Controller;
use Site\Controller\BlogPost; use Site\Controller\BlogPost;
use Site\Controller\Mods; use Site\Controller\Mods;
use Std\Lib\Activitypub; use Std\Lib\Activitypub;
use LogType;
class Fediverse extends BlogPost { class Fediverse extends BlogPost {
use Mods; use Mods;
@@ -98,7 +99,7 @@ class Fediverse extends BlogPost {
exit; exit;
} }
logger(\LogType::ActivityPub, "受付に入れた:".json_encode($activity)); logger(LogType::ActivityPub, "受付に入れた:".json_encode($activity));
try { try {
header('Content-Type: application/activity+json'); header('Content-Type: application/activity+json');

View File

@@ -43,6 +43,7 @@ use Std\Lib\Activitypub;
use Std\Lib\Auth; use Std\Lib\Auth;
use Std\Lib\Markdown; use Std\Lib\Markdown;
use Std\Lib\Template; use Std\Lib\Template;
use Roles;
class Home extends BlogPost { class Home extends BlogPost {
use Mods; use Mods;
@@ -149,9 +150,9 @@ class Home extends BlogPost {
// ユーザー // ユーザー
$auth = new Auth(); $auth = new Auth();
$user = $auth->getLoggedInUser(); $user = $auth->getLoggedInUser();
$isMember = $user !== NULL && $user->role !== \Roles::BANNED; $isMember = $user !== NULL && $user->role !== Roles::BANNED;
$isPaywall = $user !== NULL && $user->role >= \Roles::SUBSCRIBER; $isPaywall = $user !== NULL && $user->role >= Roles::SUBSCRIBER;
$isStaff = $user !== NULL && $user->role & (\Roles::ADMIN | \Roles::STAFF); $isStaff = $user !== NULL && $user->role & (Roles::ADMIN | Roles::STAFF);
$tmpl->assign('user', $user); $tmpl->assign('user', $user);
$tmpl->assign('pagetit', $pagetit); $tmpl->assign('pagetit', $pagetit);

View File

@@ -46,30 +46,96 @@ use Roles;
class Op { class Op {
use Mods; use Mods;
private Template $tmpl;
private Auth $auth;
private Openprovider $op;
private string $pagetit = 'OpenProvider管理 - ';
private string $description = '';
private ?\stdClass $user;
public function __construct() {
$this->tmpl = new Template('/openprovider/');
$this->auth = new Auth();
$this->user = $this->auth->getLoggedInUser();
if ($this->user && $this->user->role & (Roles::ADMIN)) {
$this->op = new Openprovider();
$this->op->login();
}
$this->tmpl->assign('user', $this->user);
$this->tmpl->assign('curPage', 'openprovider');
$this->tmpl->assign('custCss', false);
$this->tmpl->assign('menu', $this->getMenu());
$this->tmpl->assign('description', $this->description);
$this->tmpl->addCss('openprovider');
$this->tmpl->addCss('table');
}
public function index(array $params): void { public function index(array $params): void {
try { try {
$tmpl = new Template('/openprovider/'); $this->pagetit .= 'ホーム';
$pagetit = 'OpenProvider管理 - ホーム'; $this->tmpl->assign('pagetit', $this->pagetit);
$description = '';
// ユーザー if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$auth = new Auth(); $this->tmpl->render('index');
$user = $auth->getLoggedInUser();
$tmpl->assign('user', $user);
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', false);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
if (!$user || $user->role !== Roles::ADMIN) goto noaccess;
$tmpl->addCss('table');
$tmpl->render('index');
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) {
throw new \Exception($e->getMessage());
}
}
public function opListInvoices(array $params): void {
try {
$this->pagetit .= '請求書一覧';
$this->tmpl->assign('pagetit', $this->pagetit);
if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$data = $this->op->listInvoices();
$this->tmpl->assign('data', $data->data);
$this->tmpl->render('listinvoices');
exit();
noaccess:
$this->tmpl->render('nopermission');
} catch (\Exception $e) {
throw new \Exception($e->getMessage());
}
}
public function opListPayments(array $params): void {
try {
$this->pagetit .= '請求書一覧';
$this->tmpl->assign('pagetit', $this->pagetit);
if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$data = $this->op->listPayments();
$this->tmpl->assign('data', $data->data);
$this->tmpl->render('listpayments');
exit();
noaccess:
$this->tmpl->render('nopermission');
} catch (\Exception $e) {
throw new \Exception($e->getMessage());
}
}
public function opListTransactions(array $params): void {
try {
$this->pagetit .= '請求書一覧';
$this->tmpl->assign('pagetit', $this->pagetit);
if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$data = $this->op->listTransactions();
$this->tmpl->assign('data', $data->data);
$this->tmpl->render('listtransactions');
exit();
noaccess:
$this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
@@ -77,34 +143,17 @@ class Op {
public function opListCustomers(array $params): void { public function opListCustomers(array $params): void {
try { try {
$tmpl = new Template('/openprovider/'); $this->pagetit .= '顧客様検索';
$pagetit = 'OpenProvider管理 - 顧客様検索'; $this->tmpl->assign('pagetit', $this->pagetit);
$description = '';
// ユーザー if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$auth = new Auth(); $data = $this->op->listCustomers();
$user = $auth->getLoggedInUser(); $this->tmpl->assign('data', $data->data);
$tmpl->assign('user', $user); $this->tmpl->render('listcustomers');
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', true);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
if (!$user || $user->role !== Roles::ADMIN) goto noaccess;
$op = new Openprovider();
$op->login();
$data = $op->listCustomers();
$tmpl->assign('data', $data->data);
$tmpl->addCss('table');
$tmpl->addCss('openprovider');
$tmpl->render('listcustomers');
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
@@ -159,24 +208,12 @@ class Op {
'subscriber_number' => $_POST['phone_subscriber_number'] ?? '', 'subscriber_number' => $_POST['phone_subscriber_number'] ?? '',
], ],
]; ];
$tmpl = new Template('/openprovider/'); $this->pagetit .= '顧客様の新規作成';
$pagetit = "OpenProvider管理 - 顧客様の新規作成"; $this->tmpl->assign('pagetit', $this->pagetit);
$description = '';
// ユーザー
$auth = new Auth();
$user = $auth->getLoggedInUser();
$tmpl->assign('user', $user);
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', true);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
$err = []; $err = [];
if (!$user || $user->role !== Roles::ADMIN) goto noaccess; if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
if (!empty($_POST)) { if (!empty($_POST)) {
if (NULL === $_POST['last_name'] || $_POST['last_name'] === '' if (NULL === $_POST['last_name'] || $_POST['last_name'] === ''
@@ -199,23 +236,20 @@ class Op {
if (($_POST['fax_area_code'] !== '' || $_POST['fax_subscriber_number'] !== '') && (!filter_var($_POST['fax_area_code'], FILTER_VALIDATE_INT) || !filter_var($_POST['fax_subscriber_number'], FILTER_VALIDATE_INT))) $err[] = 'FAXは数字をご入力下さい。'; if (($_POST['fax_area_code'] !== '' || $_POST['fax_subscriber_number'] !== '') && (!filter_var($_POST['fax_area_code'], FILTER_VALIDATE_INT) || !filter_var($_POST['fax_subscriber_number'], FILTER_VALIDATE_INT))) $err[] = 'FAXは数字をご入力下さい。';
if (!empty($err)) goto render; if (!empty($err)) goto render;
$op = new Openprovider(); $data = $this->op->createCustomer($payload, true);
$op->login();
$data = $op->createCustomer($payload, true);
header("Location: /openprovider/getcustomer/{$data->data['data']['handle']}"); header("Location: /openprovider/getcustomer/{$data->data['data']['handle']}");
exit(); exit();
} }
render: render:
$tmpl->assign('err', $err); $this->tmpl->assign('err', $err);
$tmpl->assign('data', $payload); $this->tmpl->assign('data', $payload);
$tmpl->addCss('openprovider'); $this->tmpl->render('createcustomer');
$tmpl->render('createcustomer');
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
@@ -229,34 +263,17 @@ class Op {
header('Location: /openprovider/listcustomers'); header('Location: /openprovider/listcustomers');
exit(); exit();
} }
$tmpl = new Template('/openprovider/'); $this->pagetit .= "顧客様「{$handle}」の表示";
$pagetit = "OpenProvider管理 - 顧客様「{$handle}」の表示"; $this->tmpl->assign('pagetit', $this->pagetit);
$description = '';
// ユーザー if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$auth = new Auth(); $data = $this->op->getCustomer($handle, true);
$user = $auth->getLoggedInUser(); $this->tmpl->assign('data', $data->data);
$tmpl->assign('user', $user); $this->tmpl->render('getcustomer');
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', true);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
if (!$user || $user->role !== Roles::ADMIN) goto noaccess;
$op = new Openprovider();
$op->login();
$data = $op->getCustomer($handle, true);
$tmpl->assign('data', $data->data);
$tmpl->addCss('table');
$tmpl->addCss('openprovider');
$tmpl->render('getcustomer');
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
@@ -271,44 +288,29 @@ class Op {
exit(); exit();
} }
assert_not_null($handle); assert_not_null($handle);
$tmpl = new Template('/openprovider/'); $this->pagetit .= "顧客様「{$handle}」の表示";
$pagetit = "OpenProvider管理 - 顧客様「{$handle}」の表示"; $this->tmpl->assign('pagetit', $this->pagetit);
$description = '';
// ユーザー if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$auth = new Auth();
$user = $auth->getLoggedInUser();
$tmpl->assign('user', $user);
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', true);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
if (!$user || $user->role !== Roles::ADMIN) goto noaccess;
if (empty($_POST)) goto render_confirm; if (empty($_POST)) goto render_confirm;
if (isset($_POST['delete_reject'])) { if (isset($_POST['delete_reject'])) {
header("Location: /openprovider/getcustomer/{$handle}"); header("Location: /openprovider/getcustomer/{$handle}");
exit(); exit();
} else if (isset($_POST['delete_confirm'])) { } else if (isset($_POST['delete_confirm'])) {
$op = new Openprovider(); $this->op->deleteCustomer($handle);
$op->login();
$op->deleteCustomer($handle);
} }
header('Location: /openprovider/listcustomers'); header('Location: /openprovider/listcustomers');
exit(); exit();
render_confirm: render_confirm:
$tmpl->assign('handle', $handle); $this->tmpl->assign('handle', $handle);
$tmpl->addCss('openprovider'); $this->tmpl->render('deletecustomer');
$tmpl->render('deletecustomer');
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
@@ -316,33 +318,17 @@ class Op {
public function opListTlds(array $params): void { public function opListTlds(array $params): void {
try { try {
$tmpl = new Template('/openprovider/'); $this->pagetit .= 'TLD一覧';
$pagetit = 'OpenProvider管理 - TLD一覧'; $this->tmpl->assign('pagetit', $this->pagetit);
$description = '';
// ユーザー if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$auth = new Auth(); $data = $this->op->listTlds();
$user = $auth->getLoggedInUser(); $this->tmpl->assign('data', $data->data);
$tmpl->assign('user', $user); $this->tmpl->render('listtlds');
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', false);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
if (!$user || $user->role !== Roles::ADMIN) goto noaccess;
$op = new Openprovider();
$op->login();
$data = $op->listTlds();
$tmpl->assign('data', $data->data);
$tmpl->addCss('table');
$tmpl->render('listtlds');
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
@@ -356,33 +342,17 @@ class Op {
header('Location: /'); header('Location: /');
exit(); exit();
} }
$tmpl = new Template('/openprovider/'); $this->pagetit .= "{$tld}の表示";
$pagetit = "OpenProvider管理 - .{$tld}の表示"; $this->tmpl->assign('pagetit', $this->pagetit);
$description = '';
// ユーザー if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$auth = new Auth(); $data = $this->op->getTld($tld);
$user = $auth->getLoggedInUser(); $this->tmpl->assign('data', $data->data);
$tmpl->assign('user', $user); $this->tmpl->render('gettld');
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', false);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
if (!$user || $user->role !== Roles::ADMIN) goto noaccess;
$op = new Openprovider();
$op->login();
$data = $op->getTld($tld);
$tmpl->assign('data', $data->data);
$tmpl->addCss('table');
$tmpl->render('gettld');
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
@@ -390,36 +360,17 @@ class Op {
public function opListDomains(array $params): void { public function opListDomains(array $params): void {
try { try {
$tmpl = new Template('/openprovider/'); $this->pagetit .= 'ドメイン確認';
$pagetit = 'OpenProvider管理 - ドメイン確認'; $this->tmpl->assign('pagetit', $this->pagetit);
$description = '';
// ユーザー if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$auth = new Auth(); $data = $this->op->listDomains($domains, true);
$user = $auth->getLoggedInUser(); $this->tmpl->assign('data', $data->data);
$tmpl->assign('user', $user); $this->tmpl->render('checkdomain');
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', false);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
if (!$user || $user->role !== Roles::ADMIN) goto noaccess;
$op = new Openprovider();
$op->login();
$data = $op->listDomains($domains, true);
$tmpl->assign('data', $data->data);
$tmpl->assign('saved', $saved);
$tmpl->addCss('table');
$tmpl->addCss('openprovider');
$tmpl->render('checkdomain');
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
@@ -429,40 +380,22 @@ class Op {
try { try {
$domains = isset($_GET['domains']) ? explode("\n", $_GET['domains']) : []; $domains = isset($_GET['domains']) ? explode("\n", $_GET['domains']) : [];
$saved = ''; $saved = '';
$this->pagetit .= 'ドメイン確認';
$this->tmpl->assign('pagetit', $this->pagetit);
$tmpl = new Template('/openprovider/'); if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$pagetit = 'OpenProvider管理 - ドメイン確認';
$description = '';
// ユーザー
$auth = new Auth();
$user = $auth->getLoggedInUser();
$tmpl->assign('user', $user);
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', false);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
if (!$user || $user->role !== Roles::ADMIN) goto noaccess;
$op = new Openprovider();
$op->login();
if (!empty($domains)) { if (!empty($domains)) {
$data = $op->checkDomainAvailable($domains, true); $data = $this->op->checkDomainAvailable($domains, true);
$tmpl->assign('data', $data->data); $this->tmpl->assign('data', $data->data);
$saved = $_GET['domains']; $saved = $_GET['domains'];
} }
$tmpl->assign('saved', $saved); $this->tmpl->assign('saved', $saved);
$this->tmpl->render('checkdomain');
$tmpl->addCss('table');
$tmpl->addCss('openprovider');
$tmpl->render('checkdomain');
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
@@ -472,34 +405,17 @@ class Op {
try { try {
$domainname = $_GET['domain_name'] ?? ''; $domainname = $_GET['domain_name'] ?? '';
$domainext = $_GET['domain_extension'] ?? ''; $domainext = $_GET['domain_extension'] ?? '';
$this->pagetit .= 'ドメイン値段一覧';
$this->tmpl->assign('pagetit', $this->pagetit);
$tmpl = new Template('/openprovider/'); if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$pagetit = 'OpenProvider管理 - ドメイン値段一覧'; $data = $this->op->getDomainPrices(['domain.name' => $domainname, 'domain.extension' => $domainext]);
$description = ''; $this->tmpl->assign('data', $data->data);
$this->tmpl->render('getdomainprices');
// ユーザー
$auth = new Auth();
$user = $auth->getLoggedInUser();
$tmpl->assign('user', $user);
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', false);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
if (!$user || $user->role !== Roles::ADMIN) goto noaccess;
$op = new Openprovider();
$op->login();
$data = $op->getDomainPrices(['domain.name' => $domainname, 'domain.extension' => $domainext]);
$tmpl->assign('data', $data->data);
$tmpl->addCss('table');
$tmpl->render('getdomainprices');
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
@@ -507,34 +423,17 @@ class Op {
public function opListDns(array $params): void { public function opListDns(array $params): void {
try { try {
$tmpl = new Template('/openprovider/'); $this->pagetit .= 'DNS一覧';
$pagetit = "OpenProvider管理 - DNS一覧"; $this->tmpl->assign('pagetit', $this->pagetit);
$description = '';
// ユーザー if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$auth = new Auth(); $data = $this->op->listDnsZones();
$user = $auth->getLoggedInUser(); $this->tmpl->assign('data', $data->data);
$tmpl->assign('user', $user); $this->tmpl->render('listdnszones');
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', true);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
if (!$user || $user->role !== Roles::ADMIN) goto noaccess;
$op = new Openprovider();
$op->login();
$data = $op->listDnsZones();
$tmpl->assign('data', $data->data);
$tmpl->addCss('table');
if ($user && $user->role & (Roles::ADMIN)) $tmpl->render('listdnszones');
else goto noaccess;
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }
@@ -548,33 +447,17 @@ class Op {
header('Location: /'); header('Location: /');
exit(); exit();
} }
$tmpl = new Template('/openprovider/'); $this->pagetit .= "{$domain}のDNS管理";
$pagetit = "OpenProvider管理 - {$domain}のDNS管理"; $this->tmpl->assign('pagetit', $this->pagetit);
$description = '';
// ユーザー if (!$this->user || $this->user->role !== Roles::ADMIN) goto noaccess;
$auth = new Auth(); $data = ['rec' => $this->op->listZoneRecords($domain), 'zone' => $this->op->getDnsZone($domain)];
$user = $auth->getLoggedInUser(); $this->tmpl->assign('data', $data->data);
$tmpl->assign('user', $user); $this->tmpl->render('getdns');
$tmpl->assign('pagetit', $pagetit);
$tmpl->assign('curPage', 'openprovider');
$tmpl->assign('custCss', false);
$tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description);
if (!$user || $user->role !== Roles::ADMIN) goto noaccess;
$op = new Openprovider();
$op->login();
$data = ['rec' => $op->listZoneRecords($domain), 'zone' => $op->getDnsZone($domain)];
$tmpl->assign('data', $data->data);
$tmpl->addCss('table');
$tmpl->render('getdns');
exit(); exit();
noaccess: noaccess:
$tmpl->render('nopermission'); $this->tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
} }

View File

@@ -40,6 +40,7 @@ namespace Site\Controller;
use Site\Controller\Mods; use Site\Controller\Mods;
use Std\Lib\Auth; use Std\Lib\Auth;
use Std\Lib\Template; use Std\Lib\Template;
use Roles;
class Page { class Page {
use Mods; use Mods;
@@ -132,7 +133,7 @@ class Page {
$tmpl->assign('menu', $this->getMenu()); $tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description); $tmpl->assign('description', $description);
if ($user && $user->role !== \Roles::BANNED) $tmpl->render('memberonly'); if ($user && $user->role !== Roles::BANNED) $tmpl->render('memberonly');
else $tmpl->render('nopermission'); else $tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());
@@ -156,7 +157,7 @@ class Page {
$tmpl->assign('menu', $this->getMenu()); $tmpl->assign('menu', $this->getMenu());
$tmpl->assign('description', $description); $tmpl->assign('description', $description);
if ($user && $user->role & (\Roles::ADMIN | \Roles::STAFF)) $tmpl->render('staffonly'); if ($user && $user->role & (Roles::ADMIN | Roles::STAFF)) $tmpl->render('staffonly');
else $tmpl->render('nopermission'); else $tmpl->render('nopermission');
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \Exception($e->getMessage()); throw new \Exception($e->getMessage());

View File

@@ -38,6 +38,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
namespace Std\Lib; namespace Std\Lib;
use Std\Lib\Curl; use Std\Lib\Curl;
use LogType;
/** /**
* ActivityPubプロトコルの実装クラス * ActivityPubプロトコルの実装クラス
@@ -434,7 +435,7 @@ class ActivityPub {
$privFile = FEDIINFO['privkey']; $privFile = FEDIINFO['privkey'];
$priv = file_get_contents($privFile); $priv = file_get_contents($privFile);
if ($priv === false) { if ($priv === false) {
logger(\LogType::ActivityPub, "エラー:秘密鍵「{$privFile}」の読込に失敗"); logger(LogType::ActivityPub, "エラー:秘密鍵「{$privFile}」の読込に失敗");
header('HTTP/1.1 500 Internal Server Error'); header('HTTP/1.1 500 Internal Server Error');
header('Content-Type: application/activity+json'); header('Content-Type: application/activity+json');
echo json_encode(['error' => '秘密鍵の読込に失敗']); echo json_encode(['error' => '秘密鍵の読込に失敗']);
@@ -454,11 +455,11 @@ class ActivityPub {
]; ];
$stringToSign = "host: {$headers['Host']}\n"."date: {$headers['Date']}\n"."digest: {$headers['Digest']}"; $stringToSign = "host: {$headers['Host']}\n"."date: {$headers['Date']}\n"."digest: {$headers['Digest']}";
logger(\LogType::ActivityPub, "署名対象: {$stringToSign}"); logger(LogType::ActivityPub, "署名対象: {$stringToSign}");
if (!openssl_sign($stringToSign, $signature, $priv, OPENSSL_ALGO_SHA256)) { if (!openssl_sign($stringToSign, $signature, $priv, OPENSSL_ALGO_SHA256)) {
$error = openssl_error_string(); $error = openssl_error_string();
logger(\LogType::ActivityPub, "エラー:署名に失敗: {$error}"); logger(LogType::ActivityPub, "エラー:署名に失敗: {$error}");
header('HTTP/1.1 500 Internal Server Error'); header('HTTP/1.1 500 Internal Server Error');
header('Content-Type: application/activity+json'); header('Content-Type: application/activity+json');
echo json_encode(['error' => '署名に失敗']); echo json_encode(['error' => '署名に失敗']);
@@ -470,7 +471,7 @@ class ActivityPub {
$headers['Signature'] .= 'algorithm="rsa-sha256",'; $headers['Signature'] .= 'algorithm="rsa-sha256",';
$headers['Signature'] .= 'headers="host date digest",'; $headers['Signature'] .= 'headers="host date digest",';
$headers['Signature'] .= 'signature="'.$sigValue.'"'; $headers['Signature'] .= 'signature="'.$sigValue.'"';
logger(\LogType::ActivityPub, "署名: {$headers['Signature']}\n送信データ: {$body}"); logger(LogType::ActivityPub, "署名: {$headers['Signature']}\n送信データ: {$body}");
$curl = new Curl($inboxUrl); $curl = new Curl($inboxUrl);
$curl->setMethod('POST') $curl->setMethod('POST')
@@ -486,9 +487,9 @@ class ActivityPub {
$err = $curl->getError(); $err = $curl->getError();
var_dump(print_r($res)); var_dump(print_r($res));
logger(\LogType::ActivityPub, "アクティビティは「{$inboxUrl}」に送信しました: HTTP {$code}"); logger(LogType::ActivityPub, "アクティビティは「{$inboxUrl}」に送信しました: HTTP {$code}");
logger(\LogType::ActivityPub, "エラー: {$err}"); logger(LogType::ActivityPub, "エラー: {$err}");
logger(\LogType::ActivityPub, "レスポンス: {$res}"); logger(LogType::ActivityPub, "レスポンス: {$res}");
} }
/** /**
@@ -571,10 +572,10 @@ class ActivityPub {
->setMaxRedirects(5) ->setMaxRedirects(5)
->setCaInfo('/etc/ssl/cert.pem'); ->setCaInfo('/etc/ssl/cert.pem');
logger(\LogType::ActivityPub, "アクターURLにリクエスト: {$actor}"); logger(LogType::ActivityPub, "アクターURLにリクエスト: {$actor}");
$success = $curl->execute(); $success = $curl->execute();
if (!$success) { if (!$success) {
logger(\LogType::ActivityPub, "アクターリクエストに失敗: ".$curl->getError()); logger(LogType::ActivityPub, "アクターリクエストに失敗: ".$curl->getError());
return null; return null;
} }
@@ -583,7 +584,7 @@ class ActivityPub {
$err = $curl->getError(); $err = $curl->getError();
if ($code !== 200) { if ($code !== 200) {
logger(\LogType::ActivityPub, "アクター取得に失敗: HTTP {$code}, エラー: {$err}"); logger(LogType::ActivityPub, "アクター取得に失敗: HTTP {$code}, エラー: {$err}");
return null; return null;
} }

View File

@@ -37,6 +37,11 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
namespace Std\Lib; namespace Std\Lib;
use Gender;
use LogType;
use Result;
use Roles;
class Auth { class Auth {
private int $id; private int $id;
@@ -72,22 +77,22 @@ class Auth {
unset($user->password); unset($user->password);
unset($user->tokens); unset($user->tokens);
$myself = $this->getUserData(); $myself = $this->getUserData();
if (!$myself || ($myself->id != $user->id && $myself->role < \Roles::STAFF)) $user->email = '(秘密)'; if (!$myself || ($myself->id != $user->id && $myself->role < Roles::STAFF)) $user->email = '(秘密)';
$user->name = namecolor($user); $user->name = namecolor($user);
$user->regDate = date('Y年m月d日', $user->regDate); $user->regDate = date('Y年m月d日', $user->regDate);
$user->gender = $user->gender === \Gender::MALE ? '男' : ($user->gender === \Gender::FEMALE ? '女' : '不明'); $user->gender = $user->gender === Gender::MALE ? '男' : ($user->gender === Gender::FEMALE ? '女' : '不明');
switch (true) { switch (true) {
case ($user->role & \Roles::ADMIN): case ($user->role & Roles::ADMIN):
$user->role = '管理者'; $user->role = '管理者';
break; break;
case ($user->role & \Roles::STAFF): case ($user->role & Roles::STAFF):
$user->role = '076スタジオの会社員'; $user->role = '076スタジオの会社員';
break; break;
case ($user->role & (\Roles::FSUBSCRIBER | \Roles::PSUBSCRIBER | \Roles::NSUBSCRIBER | \Roles::SUBSCRIBER)): case ($user->role & (Roles::FSUBSCRIBER | Roles::PSUBSCRIBER | Roles::NSUBSCRIBER | Roles::SUBSCRIBER)):
$user->role = '支援者♡'; $user->role = '支援者♡';
break; break;
case ($user->role & \Roles::BANNED): case ($user->role & Roles::BANNED):
$user->role = 'BANされた'; $user->role = 'BANされた';
break; break;
default: default:
@@ -103,14 +108,14 @@ class Auth {
return $user; return $user;
} }
public function setToken(string $username, #[SensitiveParameter] string $password): \Result { public function setToken(string $username, #[SensitiveParameter] string $password): Result {
if (!AUTH_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!AUTH_ENABLED) return Result::Error('エラー:認証システムは無効です。');
$userData = $this->getUserData(); $userData = $this->getUserData();
if (!isset($userData->tokens) || !is_array($userData->tokens)) $userData->tokens = []; if (!isset($userData->tokens) || !is_array($userData->tokens)) $userData->tokens = [];
$verify = $this->verifyLogin($username, $password); $verify = $this->verifyLogin($username, $password);
if (!$verify->isSuccess) { if (!$verify->isSuccess) {
return \Result::error($verify->message); return Result::error($verify->message);
} }
$ip = $_SERVER['REMOTE_ADDR']; $ip = $_SERVER['REMOTE_ADDR'];
@@ -119,7 +124,9 @@ class Auth {
$ip = trim($ipList[0]); $ip = trim($ipList[0]);
} }
$userData = $this->purgeOldTokens($userData); $res = $this->purgeOldTokens($userData);
if (!$res->isSuccess) return Result::Error($res->message);
$userData = $res->data;
$token = bin2hex(random_bytes(64)); $token = bin2hex(random_bytes(64));
$expire = time() + $this->tokenDuration; $expire = time() + $this->tokenDuration;
$newToken = [ $newToken = [
@@ -137,8 +144,8 @@ class Auth {
$json = json_encode($userData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); $json = json_encode($userData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if (file_put_contents($path, $json) === false) { if (file_put_contents($path, $json) === false) {
logger(\LogType::Auth, '【setToken】JSONファイルにユーザーデータを保存出来なかった。パス'.$path); logger(LogType::Auth, '【setToken】JSONファイルにユーザーデータを保存出来なかった。パス'.$path);
return \Result::error('エラー:ユーザーデータの保存に失敗。'); return Result::error('エラー:ユーザーデータの保存に失敗。');
} }
if (!setcookie('kerozen', $token, [ if (!setcookie('kerozen', $token, [
@@ -149,22 +156,24 @@ class Auth {
'httponly' => true, 'httponly' => true,
'samesite' => 'Strict' 'samesite' => 'Strict'
])) { ])) {
logger(\LogType::Auth, '【setToken】クッキーを設定出来なかった。トークン'.$token); logger(LogType::Auth, '【setToken】クッキーを設定出来なかった。トークン'.$token);
return \Result::error('エラー:クッキーを設定に失敗。'); return Result::error('エラー:クッキーを設定に失敗。');
} }
return \Result::success('ログイン成功'); return Result::success('ログイン成功');
} }
public function getToken(): string { public function getToken(): ?string {
if (!AUTH_ENABLED) return ''; if (!AUTH_ENABLED) return '';
$userData = $this->getUserData(); $userData = $this->getUserData();
if (!isset($userData->tokens) || !is_array($userData->tokens)) $userData->tokens = []; if (!isset($userData->tokens) || !is_array($userData->tokens)) $userData->tokens = [];
$userData = $this->purgeOldTokens($userData); $res = $this->purgeOldTokens($userData);
if (!$res->isSuccess) return null;
$userData = $res->data;
} }
public function logout(?string $token = null): \Result { public function logout(?string $token = null): Result {
if (!AUTH_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!AUTH_ENABLED) return Result::Error('エラー:認証システムは無効です。');
$userData = $this->getUserData(); $userData = $this->getUserData();
if (!$token) { if (!$token) {
@@ -182,27 +191,27 @@ class Auth {
'samesite' => 'Strict' 'samesite' => 'Strict'
]); ]);
return \Result::success(); return Result::success();
} }
public function isUserExist(?string $username = null): \Result { public function isUserExist(?string $username = null): Result {
if (!AUTH_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!AUTH_ENABLED) return Result::Error('エラー:認証システムは無効です。');
if (null === $username) return \Result::Error('エラー:ユーザー名をご入力下さい。'); if (null === $username) return Result::Error('エラー:ユーザー名をご入力下さい。');
$userList = scandir($this->dataDir); $userList = scandir($this->dataDir);
foreach ($userList as $list) { foreach ($userList as $list) {
if ($list === '.kara' || $list === '.' || $list === '..') continue; if ($list === '.kara' || $list === '.' || $list === '..') continue;
$file = str_replace('.json', '', $list); $file = str_replace('.json', '', $list);
$user = explode('.', $file)[1]; $user = explode('.', $file)[1];
if ($username === $user) return \Result::Success("ユーザー「{$username}」は既に存在します。"); if ($username === $user) return Result::Success("ユーザー「{$username}」は既に存在します。");
} }
return \Result::Error(''); return Result::Error('');
} }
public function mkUser(?string $username = null, #[SensitiveParameter] ?string $password = null, ?string $passwordVerify = null, ?string $email = null): \Result { public function mkUser(?string $username = null, #[SensitiveParameter] ?string $password = null, ?string $passwordVerify = null, ?string $email = null): Result {
if (!AUTH_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!AUTH_ENABLED) return Result::Error('エラー:認証システムは無効です。');
if (!AUTH_REGISTER_ENABLED) return \Result::Error('ユーザー登録は無効です。'); if (!AUTH_REGISTER_ENABLED) return Result::Error('ユーザー登録は無効です。');
$resUsr = $this->verifyUsername($username); $resUsr = $this->verifyUsername($username);
$resPwd = $this->verifyPassword($password, $passwordVerify); $resPwd = $this->verifyPassword($password, $passwordVerify);
$resEml = $this->verifyEmail($email); $resEml = $this->verifyEmail($email);
@@ -213,12 +222,12 @@ class Auth {
if (!$resPwd->isSuccess) $err .= $resPwd->message."<br />"; if (!$resPwd->isSuccess) $err .= $resPwd->message."<br />";
if (!$resEml->isSuccess) $err .= $resEml->message."<br />"; if (!$resEml->isSuccess) $err .= $resEml->message."<br />";
if ($err != '') return \Result::Error($err); if ($err != '') return Result::Error($err);
$err = ''; $err = '';
if (!mkdir($this->assDir.$username, 0755)) { if (!mkdir($this->assDir.$username, 0755)) {
logger(\LogType::Auth, '【mkUser】アセットディレクトリを作成出来なかった。chownをご確認下さい。パス'.$this->assDir.$username); logger(LogType::Auth, '【mkUser】アセットディレクトリを作成出来なかった。chownをご確認下さい。パス'.$this->assDir.$username);
return \Result::Error('エラー:ユーザーのアイコンディレクトリの作成に失敗。'); return Result::Error('エラー:ユーザーのアイコンディレクトリの作成に失敗。');
} }
$file = scandir($this->dataDir); $file = scandir($this->dataDir);
@@ -246,29 +255,29 @@ class Auth {
$user->regDate = time(); $user->regDate = time();
$user->namecolor = ''; $user->namecolor = '';
$user->displayname = ''; $user->displayname = '';
$user->gender = \Gender::UNKNOWN; $user->gender = Gender::UNKNOWN;
$user->role = \Roles::MEMBER; $user->role = Roles::MEMBER;
$user->tokens = []; $user->tokens = [];
$path = "{$this->dataDir}{$lastId}.{$username}.json"; $path = "{$this->dataDir}{$lastId}.{$username}.json";
$json = json_encode($user, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); $json = json_encode($user, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if (file_put_contents($path, $json) === false) { if (file_put_contents($path, $json) === false) {
logger(\LogType::Auth, '【mkUser】JSONファイルを作成出来なかった。パス'.$path); logger(LogType::Auth, '【mkUser】JSONファイルを作成出来なかった。パス'.$path);
rmdir($this->assDir.$username); rmdir($this->assDir.$username);
return \Result::Error('エラー:ユーザーデータの保存に失敗。'); return Result::Error('エラー:ユーザーデータの保存に失敗。');
} }
return \Result::Success(); return Result::Success();
} }
//////////////////// ////////////////////
private function verifyLogin(string $username, #[SensitiveParameter] string $password): \Result { private function verifyLogin(string $username, #[SensitiveParameter] string $password): Result {
if (!AUTH_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!AUTH_ENABLED) return Result::Error('エラー:認証システムは無効です。');
$userData = $this->getUserData(); $userData = $this->getUserData();
if ($username !== $userData->username || !password_verify($password, $userData->password)) { if ($username !== $userData->username || !password_verify($password, $userData->password)) {
return \Result::Error('エラー:ユーザー名又はパスワードが一致していません。'); return Result::Error('エラー:ユーザー名又はパスワードが一致していません。');
} }
if (password_needs_rehash($userData->password, $this->algo)) { if (password_needs_rehash($userData->password, $this->algo)) {
@@ -277,31 +286,31 @@ class Auth {
$json = json_encode($userData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); $json = json_encode($userData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if (file_put_contents($path, $json) === false) { if (file_put_contents($path, $json) === false) {
logger(\LogType::Auth, '【verifyLogin】JSONファイルを変更出来なかった。chownをご確認下さい。パス'.$path); logger(LogType::Auth, '【verifyLogin】JSONファイルを変更出来なかった。chownをご確認下さい。パス'.$path);
return \Result::Error('エラー:ユーザーデータの保存に失敗。'); return Result::Error('エラー:ユーザーデータの保存に失敗。');
} }
} }
return \Result::Success(); return Result::Success();
} }
private function purgeOldTokens(\stdClass $userData): \stdClass|\Result { private function purgeOldTokens(\stdClass $userData): Result {
if (!AUTH_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!AUTH_ENABLED) return Result::Error('エラー:認証システムは無効です。');
// 有効期限切れたトークンの削除 // 有効期限切れたトークンの削除
$out = $userData; $out = $userData;
$out->tokens = array_filter($userData->tokens, function($t): bool { $out->tokens = array_filter($userData->tokens, function($t): bool {
return ($t->expDate ?? 0) > time(); return Result::Success('', ($t->expDate ?? 0) > time());
}); });
$path = $this->dataDir.$userData->id.'.'.$userData->username.'.json'; $path = $this->dataDir.$userData->id.'.'.$userData->username.'.json';
$json = json_encode($userData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); $json = json_encode($userData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if (file_put_contents($path, $json) === false) { if (file_put_contents($path, $json) === false) {
logger(\LogType::Auth, '【purgeOldTokens】JSONファイルを変更出来なかった。chownをご確認下さい。パス'.$path); logger(LogType::Auth, '【purgeOldTokens】JSONファイルを変更出来なかった。chownをご確認下さい。パス'.$path);
return \Result::Error('エラー:ユーザーデータの保存に失敗。'); return Result::Error('エラー:ユーザーデータの保存に失敗。');
} }
return $out; return Result::Success('', $out);
} }
private function getUserId(?string $username = null, ?string $token = null): int { private function getUserId(?string $username = null, ?string $token = null): int {
@@ -396,8 +405,8 @@ class Auth {
return json_decode($lines); return json_decode($lines);
} }
private function isEmailExist(?string $email = null): \Result { private function isEmailExist(?string $email = null): Result {
if (!AUTH_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!AUTH_ENABLED) return Result::Error('エラー:認証システムは無効です。');
$userList = scandir($this->dataDir); $userList = scandir($this->dataDir);
$matches = []; $matches = [];
@@ -410,67 +419,67 @@ class Auth {
if (str_contains($content, '"email": "'.$email.'",')) { if (str_contains($content, '"email": "'.$email.'",')) {
$matches[] = $email; $matches[] = $email;
} }
if (count($matches) > 0) return \Result::Error("ユーザー「{$email}」は既に存在します。"); if (count($matches) > 0) return Result::Error("ユーザー「{$email}」は既に存在します。");
} }
return \Result::Success('エラー:メールアドレスが存在しません。'); return Result::Success('エラー:メールアドレスが存在しません。');
} }
private function verifyEmail(?string $email = null): \Result { private function verifyEmail(?string $email = null): Result {
if (!AUTH_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!AUTH_ENABLED) return Result::Error('エラー:認証システムは無効です。');
if (null === $email || '' === $email) return \Result::Error('エラー:メールアドレスをご入力下さい。'); if (null === $email || '' === $email) return Result::Error('エラー:メールアドレスをご入力下さい。');
if (strpos($email, '@') === false) return \Result::Error('エラー:メールアドレスは不正です。'); if (strpos($email, '@') === false) return Result::Error('エラー:メールアドレスは不正です。');
$domain = explode('@', $email)[1]; $domain = explode('@', $email)[1];
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return \Result::Error('エラー:メールアドレスは不正です。'); return Result::Error('エラー:メールアドレスは不正です。');
} }
if (!checkdnsrr($domain, 'MX')) { if (!checkdnsrr($domain, 'MX')) {
return \Result::Error('エラー:メールアドレスは不正です。'); return Result::Error('エラー:メールアドレスは不正です。');
} }
$res = $this->isEmailExist($email); $res = $this->isEmailExist($email);
if (!$res->isSuccess) return \Result::Error($res->message); if (!$res->isSuccess) return Result::Error($res->message);
return \Result::Success(); return Result::Success();
} }
private function verifyUsername(?string $username): \Result { private function verifyUsername(?string $username): Result {
if (!AUTH_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!AUTH_ENABLED) return Result::Error('エラー:認証システムは無効です。');
if (null === $username || '' === $username) return \Result::Error('エラー:ユーザー名をご入力下さい。'); if (null === $username || '' === $username) return Result::Error('エラー:ユーザー名をご入力下さい。');
if (strlen($username) < 6) return \Result::Error('エラーユーザー名は6文字以上をご入力下さい。'); if (strlen($username) < 6) return Result::Error('エラーユーザー名は6文字以上をご入力下さい。');
$res = $this->isUserExist($username); $res = $this->isUserExist($username);
if ($res->isSuccess) return \Result::Error($res->message); if ($res->isSuccess) return Result::Error($res->message);
$accepted = 'A-Za-z0-9'; $accepted = 'A-Za-z0-9';
if (preg_match("/[^{$accepted}]/", $username)) { if (preg_match("/[^{$accepted}]/", $username)) {
return \Result::Error('エラー:ユーザー名に不正な文字が含みます。'); return Result::Error('エラー:ユーザー名に不正な文字が含みます。');
} }
return \Result::Success(); return Result::Success();
} }
private function verifyPassword(#[SensitiveParameter] ?string $password = null, #[SensitiveParameter] ?string $passwordVerify = null): \Result { private function verifyPassword(#[SensitiveParameter] ?string $password = null, #[SensitiveParameter] ?string $passwordVerify = null): Result {
if (!AUTH_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!AUTH_ENABLED) return Result::Error('エラー:認証システムは無効です。');
if (null === $password || '' === $password) return \Result::Error('エラー:パスワードをご入力下さい。'); if (null === $password || '' === $password) return Result::Error('エラー:パスワードをご入力下さい。');
if ($password !== $passwordVerify) return \Result::Error('エラー:パスワードは一致していません。'); if ($password !== $passwordVerify) return Result::Error('エラー:パスワードは一致していません。');
$res = $this->checkPasswordStandards($password); $res = $this->checkPasswordStandards($password);
if (!$res->isSuccess) { if (!$res->isSuccess) {
return \Result::Error($res->message); return Result::Error($res->message);
} }
return \Result::Success(); return Result::Success();
} }
private function checkPasswordStandards(#[SensitiveParameter] ?string $password = null): \Result { private function checkPasswordStandards(#[SensitiveParameter] ?string $password = null): Result {
if (!AUTH_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!AUTH_ENABLED) return Result::Error('エラー:認証システムは無効です。');
if (strlen($password) < $this->minPassLen) return \Result::Error("エラー:パスワードは{$this->minPassLen}以上をご入力下さい。"); if (strlen($password) < $this->minPassLen) return Result::Error("エラー:パスワードは{$this->minPassLen}以上をご入力下さい。");
if (!\countmatch($password)) { if (!\countmatch($password)) {
return \Result::Error('エラー:パスワードに不正な文字が含みます。'); return Result::Error('エラー:パスワードに不正な文字が含みます。');
} }
$countUpper = preg_match_all('/[A-Z]/', $password) < 2; $countUpper = preg_match_all('/[A-Z]/', $password) < 2;
@@ -479,9 +488,9 @@ class Auth {
$countSymbol = \count_special_chars($password) < 2; $countSymbol = \count_special_chars($password) < 2;
if ($countUpper || $countLower || $countDigit || $countSymbol) { if ($countUpper || $countLower || $countDigit || $countSymbol) {
return \Result::Error('エラーパスワードは2つ以上の大文字、2つ以上の小文字、2つ以上の数字、及び2つ以上の特別文字を含む事が必須です。'); return Result::Error('エラーパスワードは2つ以上の大文字、2つ以上の小文字、2つ以上の数字、及び2つ以上の特別文字を含む事が必須です。');
} }
return \Result::Success(); return Result::Success();
} }
}; };

View File

@@ -37,6 +37,8 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
namespace Std\Lib; namespace Std\Lib;
use Result;
/** /**
* php_curlへの依存を排除するための独自のCURL実装 * php_curlへの依存を排除するための独自のCURL実装
*/ */
@@ -317,11 +319,11 @@ class Curl {
* *
* @return Result 成功または失敗 * @return Result 成功または失敗
*/ */
public function execute(): \Result { public function execute(): Result {
if (!CURL_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (!CURL_ENABLED) return Result::Error('エラー:認証システムは無効です。');
if (empty($this->url)) { if (empty($this->url)) {
$this->responseError = 'URLがありません'; $this->responseError = 'URLがありません';
return \Result::Error($this->responseError); return Result::Error($this->responseError);
} }
// レスポンスデータのリセット // レスポンスデータのリセット
@@ -355,7 +357,7 @@ class Curl {
$parsed = parse_url($currentUrl); $parsed = parse_url($currentUrl);
if (!$parsed) { if (!$parsed) {
$this->responseError = "無効なURL: {$currentUrl}"; $this->responseError = "無効なURL: {$currentUrl}";
return \Result::Error($this->responseError); return Result::Error($this->responseError);
} }
$scheme = isset($parsed['scheme']) ? strtolower($parsed['scheme']) : 'http'; $scheme = isset($parsed['scheme']) ? strtolower($parsed['scheme']) : 'http';
@@ -476,7 +478,7 @@ class Curl {
if ($this->verbose && $this->stderr) { if ($this->verbose && $this->stderr) {
fwrite($this->stderr, "* エラー: {$this->responseError}\n"); fwrite($this->stderr, "* エラー: {$this->responseError}\n");
} }
return \Result::Error($this->responseError); return Result::Error($this->responseError);
} }
// タイムアウトを設定 // タイムアウトを設定
@@ -497,7 +499,7 @@ class Curl {
if ($rawResponse === '') { if ($rawResponse === '') {
$this->responseError = 'リスポンスエラー'; $this->responseError = 'リスポンスエラー';
return \Result::Error($this->responseError); return Result::Error($this->responseError);
} }
list($headerLines, $body) = $this->parseResponse($rawResponse); list($headerLines, $body) = $this->parseResponse($rawResponse);
@@ -559,7 +561,7 @@ class Curl {
$this->method = $originalMethod; $this->method = $originalMethod;
$this->info['total_time'] = microtime(true) - $startTime; $this->info['total_time'] = microtime(true) - $startTime;
return \Result::Success(); return Result::Success();
} }
/** /**

View File

@@ -38,6 +38,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
namespace Std\Lib\Image; namespace Std\Lib\Image;
use Std\Lib\Image\ImageInterface; use Std\Lib\Image\ImageInterface;
use LogType;
class Png implements ImageInterface { class Png implements ImageInterface {
public \stdClass $IHDR; // 画像ヘッダー public \stdClass $IHDR; // 画像ヘッダー
@@ -629,7 +630,7 @@ exif_crc:
fclose($fp); fclose($fp);
$err = '不明なチャンク:'.$nextChunk.'、HEX'.bin2hex($nextChunk); $err = '不明なチャンク:'.$nextChunk.'、HEX'.bin2hex($nextChunk);
kys($err); kys($err);
logger(\LogType::Image, '【PNG】'.$err); logger(LogType::Image, '【PNG】'.$err);
return $png; return $png;
} }

View File

@@ -37,6 +37,8 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
namespace Std\Lib; namespace Std\Lib;
use LogType;
class Mailer { class Mailer {
private $socket; private $socket;
private string $host; private string $host;
@@ -70,7 +72,7 @@ class Mailer {
$this->socket = fsockopen($this->host, $this->port, $errno, $err, 30); $this->socket = fsockopen($this->host, $this->port, $errno, $err, 30);
if (!$this->socket) { if (!$this->socket) {
$msg = "接続に失敗: {$err} ({$errno})"; $msg = "接続に失敗: {$err} ({$errno})";
logger(\LogType::Mailer, $msg); logger(LogType::Mailer, $msg);
throw new \Exception($msg); throw new \Exception($msg);
} }
@@ -104,7 +106,7 @@ class Mailer {
if (!stream_socket_enable_crypto( if (!stream_socket_enable_crypto(
$this->socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { $this->socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
$msg = "TLSハンドシェイクに失敗"; $msg = "TLSハンドシェイクに失敗";
logger(\LogType::Mailer, $msg); logger(LogType::Mailer, $msg);
throw new \Exception($msg); throw new \Exception($msg);
} }
@@ -198,7 +200,7 @@ class Mailer {
$response = $this->readResponse(); $response = $this->readResponse();
if (substr($response, 0, 3) != '250') { if (substr($response, 0, 3) != '250') {
$msg = "メール送信に失敗: {$response}"; $msg = "メール送信に失敗: {$response}";
logger(\LogType::Mailer, $msg); logger(LogType::Mailer, $msg);
throw new \Exception($msg); throw new \Exception($msg);
} }
} }
@@ -235,7 +237,7 @@ class Mailer {
$res = $this->readResponse(); $res = $this->readResponse();
if (substr($res, 0, 3) != $retcode) { if (substr($res, 0, 3) != $retcode) {
$msg = "{$command}」に対する予期しないレスポンス: {$res}"; $msg = "{$command}」に対する予期しないレスポンス: {$res}";
logger(\LogType::Mailer, $msg); logger(LogType::Mailer, $msg);
throw new \Exception($msg); throw new \Exception($msg);
} }

View File

@@ -434,6 +434,44 @@ function getImageInfo(string $url): \Std\Lib\Image {
return $img; return $img;
} }
function align(int $val): int {
if ($val <= 0) return 1;
if ($val === 1) return 1;
$res = 0;
$lower = 1;
while ($lower * 2 <= $val) $lower *= 2;
$upper = $lower * 2;
if (($val - $lower) <= ($upper - $val)) return $lower;
return $upper;
}
function align_up(int $val): int {
if ($val <= 0) return 1;
if ($val === 1) return 1;
$res = 0;
$lower = 1;
while ($lower * 2 <= $val) $lower *= 2;
$upper = $lower * 2;
return $upper;
}
function align_down(int $val): int {
if ($val <= 0) return 1;
if ($val === 1) return 1;
$res = 0;
$lower = 1;
while ($lower * 2 <= $val) $lower *= 2;
return $lower;
}
// PHP 8.3と8.4の場合 // PHP 8.3と8.4の場合
if (!function_exists('array_last')) { if (!function_exists('array_last')) {
function array_last(array $array): mixed { function array_last(array $array): mixed {

View File

@@ -1,6 +1,12 @@
{@ include(common/header) @} {@ include(common/header) @}
<h1>{{ $description }}</h1> <h1>{{ $description }}</h1>
<ul> <ul>
<li>請求</li>
<ul>
<li><a href="/openprovider/listinvoices">請求書一覧</a></li>
<li><a href="/openprovider/listpayments">支払一覧</a></li>
<li><a href="/openprovider/listtransactions">トランザクション一覧</a></li>
</ul>
<li>顧客様</li> <li>顧客様</li>
<ul> <ul>
<li><a href="/openprovider/listcustomers">顧客様検索</a></li> <li><a href="/openprovider/listcustomers">顧客様検索</a></li>

View File

@@ -0,0 +1,9 @@
{@ include(common/header) @}
<h1>請求書一覧</h1>
{@ kys($data) @}
検索バー<br />
{@ if (isset($data['data']['results'])) @}
{@ else @}
<p>何も見つけられませんでした。</p>
{@ endif @}
{@ include(common/footer) @}

View File

@@ -0,0 +1,9 @@
{@ include(common/header) @}
<h1>支払一覧</h1>
{@ kys($data) @}
検索バー<br />
{@ if (isset($data['data']['results'])) @}
{@ else @}
<p>何も見つけられませんでした。</p>
{@ endif @}
{@ include(common/footer) @}

View File

@@ -0,0 +1,39 @@
{@ include(common/header) @}
<h1>トランザクション一覧</h1>
検索バー<br />
{@ if (isset($data['data']['results'])) @}
<table>
<thead>
<tr>
<th>日時</th>
<th>状況</th>
<th>ドメイン名・商品</th>
<th>数</th>
<th>値段</th>
<th>デビット</th>
<th>クレジット</th>
</tr>
</thead>
<tbody>
{@ foreach ($data['data']['results'] as $d) @}
{$ $pp = $d['price']['product'] $}
{$ $pr = $d['price']['reseller'] $}
{$ $tp = $d['total']['product'] $}
{$ $tr = $d['total']['reseller'] $}
<tr>
<td>{{ $d['creation_date'] }}</td>
<td>{{ $d['action'] }}</td>
<td>{{ $d['subject'] }}</td>
<td>{{ $d['quantity'] }}</td>
<td>{{ $pp['price'].' '.$pp['currency'] }}<br /><span style="color: #777777;">({{ $pr['price'].' '.$pr['currency'] }})</span></td>
<td><span style="color: #ee5040;">{{ $tr['price'].' '.$tr['currency'] }}</span></td>
<td><span style="color: #14c014;"></span></td>
</tr>
{@ endforeach @}
</tbody>
</table>
<p>結果数:{{ $data['data']['total'] }}</p>
{@ else @}
<p>何も見つけられませんでした。</p>
{@ endif @}
{@ include(common/footer) @}