diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index bc4cd82..67557bf 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -4,12 +4,12 @@ This is a list of people who have contributed to Sakura and also a list of the l ## People -| Name | Contribution | -| ---- | ------------ | -| Flashwave | Project leader and main developer. | -| MallocNull | Internal advice and pointing out my (Flashwave) stupidity. | -| kamilrakowski | Providing a huge pile of security advice and fixes. | -| RandomGuy | Mostly security advice as well. | +| Name | Contribution | +| ------------- | ---------------------------------------------------------- | +| Flashwave | Project leader and main developer. | +| MallocNull | Internal advice and pointing out my (Flashwave) stupidity. | +| kamilrakowski | Providing a huge pile of security advice and fixes. | +| RandomGuy | Mostly security advice as well. | ## Libraries diff --git a/_developer_data/Sockura.php b/_developer_data/Sockura.php index 1c59006..625ea5a 100644 --- a/_developer_data/Sockura.php +++ b/_developer_data/Sockura.php @@ -7,8 +7,11 @@ // Filesystem path to the _sakura folder WITHOUT an ending / // This can also be set before an include of this file in case // you're using git to keep in sync and don't want conflicts -if(!isset($sockSakuraPath)) - $sockSakuraPath = ''; +if(!isset($sockSakuraPath)) { + + $sockSakuraPath = ''; + +} /* * * DON'T EDIT ANYTHING BELOW THIS LINE * * */ @@ -18,7 +21,8 @@ require_once $sockSakuraPath .'/sakura.php'; use sockchat\Auth; use Sakura\Session; use Sakura\Users; -use Sakura\SockChat; +use Sakura\Permissions; +use Sakura\User; if(Auth::getPageType() == AUTH_FETCH) { @@ -29,9 +33,12 @@ if(Auth::getPageType() == AUTH_FETCH) { Auth::AppendArguments([Session::$userId, Session::$sessionId]); Auth::Accept(); - } else + } else { + Auth::Deny(); + } + } else { // Get arguments @@ -41,12 +48,8 @@ if(Auth::getPageType() == AUTH_FETCH) { // Check if session is active else deny if(Session::checkSession($uid, $sid)) { - // Get user and rank data - $user = Users::getUser($uid); - $rank = Users::getRank($user['rank_main']); - - // Deny group and user id 0 - if($user['id'] == 0 || $rank['id'] == 0 || $user['password_algo'] == 'nologin') { + // Check if they can access the chat + if(Permissions::check('SITE', 'DEACTIVATED', $uid, 1) && Permissions::check('SITE', 'RESTRICTED', $uid, 1)) { Auth::Deny(); Auth::Serve(); @@ -54,39 +57,35 @@ if(Auth::getPageType() == AUTH_FETCH) { } + // Create a user object + $user = new User($uid); + // Set the user's data Auth::SetUserData( - $user['id'], - $user['username'], - $user['name_colour'] == null ? $rank['colour'] : $user['name_colour'] + $user->data['id'], + $user->data['username'], + $user->colour() ); - // Get the user's permissions - $perms = SockChat::getUserPermissions($user['id']); - - // Check if they can access the chat - if(!$perms['access']) { - - Auth::Deny(); - Auth::Serve(); - exit; - - } - // Set the common permissions Auth::SetCommonPermissions( - $perms['rank'], - $perms['type'], - $perms['logs'], - $perms['nick'], - $perms['channel'] + bindec(Permissions::getUserPermissions($uid)['SITE']), + Permissions::check('MANAGE', 'USE_MANAGE', $uid, 1) ? 1 : 0, + Permissions::check('SITE', 'CREATE_BACKGROUND', $uid, 1) ? 1 : 0, + Permissions::check('SITE', 'CHANGE_USERNAME', $uid, 1) ? 1 : 0, + Permissions::check('SITE', 'MULTIPLE_GROUPS', $uid, 1) ? 2 : ( + Permissions::check('SITE', 'CREATE_GROUP', $uid, 1) ? 1 : 0 + ) ); Auth::Accept(); - } else + } else { + Auth::Deny(); + } + } // Serve the authentication data diff --git a/_developer_data/structure.sql b/_developer_data/structure.sql index 498fdd2..4c70568 100644 --- a/_developer_data/structure.sql +++ b/_developer_data/structure.sql @@ -5,8 +5,6 @@ SET time_zone = '+00:00'; SET foreign_key_checks = 0; SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; -DROP DATABASE IF EXISTS `sakura-development`; -CREATE DATABASE `sakura-development` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */; USE `sakura-development`; DROP TABLE IF EXISTS `sakura_actioncodes`; @@ -17,7 +15,7 @@ CREATE TABLE `sakura_actioncodes` ( `actkey` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'The URL key for using this code.', `instruction` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Things the backend should do upon using this code', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `sakura_apikeys`; @@ -54,7 +52,7 @@ CREATE TABLE `sakura_bbcodes` ( `description` varchar(512) COLLATE utf8_bin NOT NULL COMMENT 'Description of what this does.', `on_posting` tinyint(1) unsigned NOT NULL COMMENT 'Set if this bbcode is displayed on the posting page.', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; INSERT INTO `sakura_bbcodes` (`id`, `regex`, `replace`, `title`, `description`, `on_posting`) VALUES (1, '/\\[b\\](.*?)\\[\\/b\\]/is', '$1', 'Bold', 'Make text bold. Usage: [b]text[/b].', 1), @@ -65,8 +63,7 @@ INSERT INTO `sakura_bbcodes` (`id`, `regex`, `replace`, `title`, `description`, (6, '/\\[url=([a-zA-Z0-9\\.\\$\\-\\_\\.\\+\\*\\!\\\'\\(\\)\\/\\:\\#]+)\\](.*?)\\[\\/url\\]/is', '$2', 'Link', 'Embed a URL. Usage: [url=http://google.com]Link to google![/url]', 0), (7, '/\\[url\\]([a-zA-Z0-9\\.\\$\\-\\_\\.\\+\\*\\!\\\'\\(\\)\\/\\:\\#]+)\\[\\/url\\]/is', '$1', 'Link', 'Make a link clickable (if the automatic algorithm doesn\'t do it already). Usage: [url]http://google.com[/url]', 1), (8, '/\\[quote\\=\\\"(.+)\\\"\\](.+)\\[\\/quote]/is', '
$1 wrote:
$2
', 'Quote', 'Quote a user\'s post. Usage: [quote=Flashwave]nookls is pretty[/quote]', 0), -(9, '/\\[quote\\](.+)\\[\\/quote]/is', '
Quote:
$1
', 'Quote', 'Quote a user\'s post. Usage: [quote]nookls is pretty[/quote]', 1) -ON DUPLICATE KEY UPDATE `id` = VALUES(`id`), `regex` = VALUES(`regex`), `replace` = VALUES(`replace`), `title` = VALUES(`title`), `description` = VALUES(`description`), `on_posting` = VALUES(`on_posting`); +(9, '/\\[quote\\](.+)\\[\\/quote]/is', '
Quote:
$1
', 'Quote', 'Quote a user\'s post. Usage: [quote]nookls is pretty[/quote]', 1); DROP TABLE IF EXISTS `sakura_config`; CREATE TABLE `sakura_config` ( @@ -83,15 +80,15 @@ INSERT INTO `sakura_config` (`config_name`, `config_value`) VALUES ('cookie_path', '/'), ('site_style', 'yuuno'), ('manage_style', 'broomcloset'), -('smtp_server', 'smtp-mail.outlook.com'), -('smtp_auth', '1'), -('smtp_secure', 'tls'), -('smtp_port', '587'), -('smtp_username', 'flashii@outlook.com'), +('smtp_server', ''), +('smtp_auth', ''), +('smtp_secure', ''), +('smtp_port', ''), +('smtp_username', ''), ('smtp_password', ''), ('smtp_replyto_mail', 'admin@flashii.net'), ('smtp_replyto_name', 'Flashwave'), -('smtp_from_email', 'flashii@outlook.com'), +('smtp_from_email', ''), ('smtp_from_name', 'Flashii Noreply'), ('sitename', 'Cutting Edgii'), ('recaptcha', '0'), @@ -117,9 +114,6 @@ INSERT INTO `sakura_config` (`config_name`, `config_value`) VALUES ('premium_amount_max', '24'), ('alumni_rank_id', '9'), ('url_main', 'flashii.test'), -('disqus_shortname', 'flashii'), -('disqus_api_key', ''), -('disqus_api_secret', ''), ('front_page_news_posts', '3'), ('date_format', 'D Y-m-d H:i:s T'), ('news_posts_per_page', '3'), @@ -131,9 +125,6 @@ INSERT INTO `sakura_config` (`config_name`, `config_value`) VALUES ('url_api', 'api.flashii.test'), ('content_path', '/content'), ('user_uploads', 'uploads'), -('no_avatar_img', 'main/content/images/no-av.png'), -('deactivated_avatar_img', 'main/content/images/deactivated-av.png'), -('banned_avatar_img', 'main/content/images/banned-av.png'), ('no_background_img', 'main/content/pixel.png'), ('no_header_img', 'main/content/images/triangles.png'), ('pixel_img', 'main/content/pixel.png'), @@ -142,8 +133,13 @@ INSERT INTO `sakura_config` (`config_name`, `config_value`) VALUES ('background_max_height', '1440'), ('background_min_height', '16'), ('background_min_width', '16'), -('max_online_time', '500') -ON DUPLICATE KEY UPDATE `config_name` = VALUES(`config_name`), `config_value` = VALUES(`config_value`); +('max_online_time', '500'), +('no_avatar_img', 'main/content/data/{{ TPL }}/images/no-av.png'), +('deactivated_avatar_img', 'main/content/data/{{ TPL }}/images/deactivated-av.png'), +('banned_avatar_img', 'main/content/data/{{ TPL }}/images/banned-av.png'), +('session_check', '2'), +('url_rewrite', '1'), +('members_per_page', '30'); DROP TABLE IF EXISTS `sakura_emoticons`; CREATE TABLE `sakura_emoticons` ( @@ -189,8 +185,7 @@ INSERT INTO `sakura_emoticons` (`emote_string`, `emote_path`) VALUES (':wtf:', '/content/images/emoticons/wtf.gif'), (':sleep:', '/content/images/emoticons/zzz.gif'), (':what:', '/content/images/emoticons/what.png'), -(':smug:', '/content/images/emoticons/smug.png') -ON DUPLICATE KEY UPDATE `emote_string` = VALUES(`emote_string`), `emote_path` = VALUES(`emote_path`); +(':smug:', '/content/images/emoticons/smug.png'); DROP TABLE IF EXISTS `sakura_faq`; CREATE TABLE `sakura_faq` ( @@ -199,7 +194,7 @@ CREATE TABLE `sakura_faq` ( `question` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'The question.', `answer` text COLLATE utf8_bin NOT NULL COMMENT 'The answer.', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `sakura_forums`; @@ -212,7 +207,7 @@ CREATE TABLE `sakura_forums` ( `forum_type` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT 'Forum type, 0 for regular board, 1 for category and 2 for link.', `forum_icon` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Display icon for the forum.', PRIMARY KEY (`forum_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `sakura_friends`; @@ -265,18 +260,19 @@ CREATE TABLE `sakura_messages` ( `subject` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Title of the message', `content` text COLLATE utf8_bin NOT NULL COMMENT 'Contents of the message.', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `sakura_news`; CREATE TABLE `sakura_news` ( - `id` bigint(128) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.', - `uid` bigint(128) unsigned NOT NULL COMMENT 'ID of user who posted this news message.', - `date` int(64) unsigned NOT NULL COMMENT 'News post timestamp.', + `id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Automatically generated ID by MySQL for management.', + `category` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Category ID.', + `uid` bigint(255) unsigned NOT NULL COMMENT 'ID of user who posted this news message.', + `date` int(11) unsigned NOT NULL COMMENT 'News post timestamp.', `title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Title of the post.', `content` text COLLATE utf8_bin NOT NULL COMMENT 'Contents of the post', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `sakura_notifications`; @@ -294,7 +290,7 @@ CREATE TABLE `sakura_notifications` ( PRIMARY KEY (`id`), KEY `uid` (`uid`), CONSTRAINT `sakura_notifications_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `sakura_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `sakura_optionfields`; @@ -308,8 +304,9 @@ CREATE TABLE `sakura_optionfields` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; INSERT INTO `sakura_optionfields` (`id`, `name`, `description`, `formtype`, `require_perm`) VALUES -('profileBackgroundSiteWide', 'Display profile background site wide', 'This will make the profile background you set on your profile appear on the entire site (except on other profiles).', 'checkbox', 'CREATE_BACKGROUND') -ON DUPLICATE KEY UPDATE `id` = VALUES(`id`), `name` = VALUES(`name`), `description` = VALUES(`description`), `formtype` = VALUES(`formtype`), `require_perm` = VALUES(`require_perm`); +('disableProfileParallax', 'Disable Parallaxing', 'This will stop your background from responding to your mouse movement, this will only affect your background.', 'checkbox', 'CHANGE_BACKGROUND'), +('profileBackgroundSiteWide', 'Display profile background site wide', 'This will make the profile background you set on your profile appear on the entire site (except on other profiles).', 'checkbox', 'CREATE_BACKGROUND'), +('useMisaki', 'Use the testing style', 'This will make the site use the new Misaki style instead of Yuuno.', 'checkbox', 'ALTER_PROFILE'); DROP TABLE IF EXISTS `sakura_permissions`; CREATE TABLE `sakura_permissions` ( @@ -322,16 +319,16 @@ CREATE TABLE `sakura_permissions` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; INSERT INTO `sakura_permissions` (`rid`, `uid`, `siteperms`, `manageperms`, `forumperms`, `rankinherit`) VALUES -(1, 0, '0000000000000000000000000001', '000', '1', '000'), -(2, 0, '0000111111111100111101101100', '000', '1', '000'), -(3, 0, '0001111111111111111111111100', '011', '1', '000'), -(4, 0, '0111111111111111111111111100', '111', '1', '000'), -(5, 0, '0001111111111111111111111100', '101', '1', '000'), -(6, 0, '0000111111111100111101101100', '000', '0', '000'), -(7, 0, '0001111111111111111111111100', '011', '1', '000'), -(8, 0, '0001111111111111111111111100', '000', '1', '000'), -(9, 0, '0001111111111111111111111100', '000', '1', '000') -ON DUPLICATE KEY UPDATE `rid` = VALUES(`rid`), `uid` = VALUES(`uid`), `siteperms` = VALUES(`siteperms`), `manageperms` = VALUES(`manageperms`), `forumperms` = VALUES(`forumperms`), `rankinherit` = VALUES(`rankinherit`); +(1, 0, '0000000000000000000000000001', '00', '0', '000'), +(2, 0, '0000111111111100111101101100', '00', '1', '000'), +(3, 0, '0001111111111111111111111100', '11', '1', '000'), +(4, 0, '1111111111111111111111111100', '11', '1', '000'), +(5, 0, '0001111111111111111111111100', '11', '1', '000'), +(6, 0, '0000111111111100111101101100', '00', '0', '000'), +(7, 0, '0001111111111111111111111100', '01', '1', '000'), +(8, 0, '0001111111111111111111111100', '00', '1', '000'), +(9, 0, '0001111111111111111111111100', '00', '1', '000'), +(10, 0, '0000000011010100101000100010', '00', '0', '000'); DROP TABLE IF EXISTS `sakura_posts`; CREATE TABLE `sakura_posts` ( @@ -355,7 +352,7 @@ CREATE TABLE `sakura_posts` ( KEY `poster_id` (`poster_id`), CONSTRAINT `sakura_posts_ibfk_1` FOREIGN KEY (`topic_id`) REFERENCES `sakura_topics` (`topic_id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `sakura_posts_ibfk_2` FOREIGN KEY (`forum_id`) REFERENCES `sakura_forums` (`forum_id`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `sakura_premium`; @@ -368,6 +365,17 @@ CREATE TABLE `sakura_premium` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +DROP TABLE IF EXISTS `sakura_premium_log`; +CREATE TABLE `sakura_premium_log` ( + `id` int(16) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.', + `uid` bigint(255) unsigned NOT NULL COMMENT 'User ID of purchaser', + `amount` float NOT NULL COMMENT 'Amount that was transferred.', + `date` int(11) unsigned NOT NULL COMMENT 'Date when the purchase was made.', + `comment` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'A short description of the action taken.', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=143 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + + DROP TABLE IF EXISTS `sakura_profilefields`; CREATE TABLE `sakura_profilefields` ( `id` int(64) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID used for ordering on the userpage.', @@ -378,7 +386,7 @@ CREATE TABLE `sakura_profilefields` ( `description` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Description of the field displayed in the control panel.', `additional` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Undocumented JSON array containing special options if needed (probably only going to be used for the YouTube field).', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; INSERT INTO `sakura_profilefields` (`id`, `name`, `formtype`, `islink`, `linkformat`, `description`, `additional`) VALUES (1, 'Website', 'url', 1, '{{ VAL }}', 'URL to your website', ''), @@ -392,8 +400,7 @@ INSERT INTO `sakura_profilefields` (`id`, `name`, `formtype`, `islink`, `linkfor (9, 'Origin', 'text', 0, '', 'Your Origin User ID', ''), (10, 'Xbox Live', 'text', 1, 'https://account.xbox.com/en-GB/Profile?Gamertag={{ VAL }}', 'Your Xbox User ID', ''), (11, 'PSN', 'text', 1, 'http://psnprofiles.com/{{ VAL }}', 'Your PSN User ID', ''), -(12, 'Last.fm', 'text', 1, 'http://last.fm/user/{{ VAL }}', 'Your Last.fm username', '') -ON DUPLICATE KEY UPDATE `id` = VALUES(`id`), `name` = VALUES(`name`), `formtype` = VALUES(`formtype`), `islink` = VALUES(`islink`), `linkformat` = VALUES(`linkformat`), `description` = VALUES(`description`), `additional` = VALUES(`additional`); +(12, 'Last.fm', 'text', 1, 'http://last.fm/user/{{ VAL }}', 'Your Last.fm username', ''); DROP TABLE IF EXISTS `sakura_ranks`; CREATE TABLE `sakura_ranks` ( @@ -405,7 +412,7 @@ CREATE TABLE `sakura_ranks` ( `description` text COLLATE utf8_bin NOT NULL COMMENT 'A description of what a user of this rank can do/is supposed to do.', `title` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Default user title if user has none set.', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; INSERT INTO `sakura_ranks` (`id`, `name`, `multi`, `hidden`, `colour`, `description`, `title`) VALUES (1, 'Deactivated', 0, 1, '#555', 'Users that are yet to be activated or that deactivated their own account.', 'Deactivated'), @@ -415,9 +422,9 @@ INSERT INTO `sakura_ranks` (`id`, `name`, `multi`, `hidden`, `colour`, `descript (5, 'Developer', 1, 0, '#824CA0', 'Users that either create or test new features of the site.', 'Staff'), (6, 'Bot', 1, 1, '#9E8DA7', 'Reserved user accounts for services.', 'Bot'), (7, 'Chat moderator', 1, 0, '#09F', 'Moderators of the chat room.', 'Staff'), -(8, 'Tenshi', 0, 0, '#EE9400', 'Users that donated $5.00 or more in order to keep the site and it\'s services alive!', 'Tenshi'), -(9, 'Alumnii', 0, 0, '#FF69B4', 'People who have contributed to the community but have moved on or resigned.', 'Alumnii') -ON DUPLICATE KEY UPDATE `id` = VALUES(`id`), `name` = VALUES(`name`), `multi` = VALUES(`multi`), `hidden` = VALUES(`hidden`), `colour` = VALUES(`colour`), `description` = VALUES(`description`), `title` = VALUES(`title`); +(8, 'Tenshi', 0, 0, '#EE9400', 'Users that bought premium to help us keep the site and its services alive!', 'Tenshi'), +(9, 'Alumnii', 0, 0, '#FF69B4', 'People who have contributed to the community but have moved on or resigned.', 'Alumnii'), +(10, 'Restricted', 0, 1, '#333', 'Users that are restricted.', 'Restricted'); DROP TABLE IF EXISTS `sakura_regcodes`; CREATE TABLE `sakura_regcodes` ( @@ -458,28 +465,9 @@ CREATE TABLE `sakura_sessions` ( PRIMARY KEY (`id`), KEY `userid` (`userid`), CONSTRAINT `sakura_sessions_ibfk_1` FOREIGN KEY (`userid`) REFERENCES `sakura_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=165 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -DROP TABLE IF EXISTS `sakura_sock_perms`; -CREATE TABLE `sakura_sock_perms` ( - `rid` bigint(128) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of rank that this permission counts for (set to 0 if user).', - `uid` bigint(255) unsigned NOT NULL DEFAULT '0' COMMENT 'ID of the user this permission counts for (set to 0 if rank).', - `perms` varchar(128) COLLATE utf8_bin NOT NULL DEFAULT '1,0,0,0,0,0' COMMENT 'Permission data (has access, in-chat rank, user type, log access, nick access, channel creation)' -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; - -INSERT INTO `sakura_sock_perms` (`rid`, `uid`, `perms`) VALUES -(1, 0, '0,0,0,0,0,0'), -(2, 0, '1,0,0,0,0,0'), -(3, 0, '1,3,1,1,1,1'), -(4, 0, '1,4,2,1,1,2'), -(5, 0, '1,2,1,1,1,1'), -(6, 0, '1,0,0,0,0,0'), -(7, 0, '1,2,1,1,1,1'), -(8, 0, '1,1,0,1,1,1'), -(9, 0, '1,1,0,1,1,1') -ON DUPLICATE KEY UPDATE `rid` = VALUES(`rid`), `uid` = VALUES(`uid`), `perms` = VALUES(`perms`); - DROP TABLE IF EXISTS `sakura_topics`; CREATE TABLE `sakura_topics` ( `topic_id` bigint(255) unsigned NOT NULL AUTO_INCREMENT COMMENT 'MySQL Generated ID used for sorting.', @@ -496,7 +484,7 @@ CREATE TABLE `sakura_topics` ( PRIMARY KEY (`topic_id`), KEY `forum_id` (`forum_id`), CONSTRAINT `sakura_topics_ibfk_1` FOREIGN KEY (`forum_id`) REFERENCES `sakura_forums` (`forum_id`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `sakura_users`; @@ -520,12 +508,12 @@ CREATE TABLE `sakura_users` ( `regdate` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Timestamp of account creation.', `lastdate` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Last time anything was done on this account.', `lastunamechange` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Last username change.', - `birthday` varchar(16) COLLATE utf8_bin DEFAULT NULL COMMENT 'Birthdate of the user.', - `country` varchar(4) COLLATE utf8_bin NOT NULL COMMENT 'Contains ISO 3166 country code of user''s registration location.', + `birthday` date DEFAULT NULL COMMENT 'Birthdate of the user.', + `country` char(2) COLLATE utf8_bin NOT NULL COMMENT 'Contains ISO 3166 country code of user''s registration location.', `userData` text COLLATE utf8_bin COMMENT 'All additional profile data.', PRIMARY KEY (`id`), UNIQUE KEY `username_clean` (`username_clean`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `sakura_warnings`; @@ -544,4 +532,4 @@ CREATE TABLE `sakura_warnings` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; --- 2015-08-21 22:06:54 +-- 2015-09-05 16:08:34 diff --git a/_sakura/changelog.json b/_sakura/changelog.json index 18e90a8..83eb030 100644 --- a/_sakura/changelog.json +++ b/_sakura/changelog.json @@ -57,7 +57,8 @@ "20150831", "20150902", "20150903", - "20150904" + "20150904", + "20150905" ] @@ -2456,6 +2457,61 @@ "user": "Flashwave" } + ], + + "20150905": [ + + { + "type": "UPD", + "change": "Finished implementation of Urls class.", + "user": "Flashwave" + }, + { + "type": "FIX", + "change": "Fully fixed the user numbering bug on the List view.", + "user": "Flashwave" + }, + { + "type": "ADD", + "change": "Added a configuration value to change how many users are displayed on the memberlist per page.", + "user": "Flashwave" + }, + { + "type": "FIX", + "change": "Made the payment cancelled message look less odd.", + "user": "Flashwave" + }, + { + "type": "FIX", + "change": "Fixed out of line padding on info pages.", + "user": "Flashwave" + }, + { + "type": "UPD", + "change": "Use Twig Blocks instead of Includes.", + "user": "Flashwave" + }, + { + "type": "FIX", + "change": "Fixed parallax disabling not working on Yuuno.", + "user": "Flashwave" + }, + { + "type": "UPD", + "change": "Implemented Urls class in PHP files.", + "user": "Flashwave" + }, + { + "type": "REM", + "change": "Dropped SockChat class and rely on system permissions from Sock Chat permissions.", + "user": "Flashwave" + }, + { + "type": "ADD", + "change": "Implemented IP checking in the session manager.", + "user": "Flashwave" + } + ] } diff --git a/_sakura/components/Hashing.php b/_sakura/components/Hashing.php index 9ea5368..2b46bd7 100644 --- a/_sakura/components/Hashing.php +++ b/_sakura/components/Hashing.php @@ -1,31 +1,31 @@ SetFrom(Configuration::getConfig('smtp_from_email'), Configuration::getConfig('smtp_from_name')); // Set the addressee - foreach($to as $email => $name) + foreach($to as $email => $name) { + $mail->AddBCC($email, $name); + } + // Subject line $mail->Subject = $subject; @@ -222,9 +225,12 @@ class Main { $mail->ClearAddresses(); // If we got an error return the error - if(!$send) + if(!$send) { + return $mail->ErrorInfo; + } + // Else just return whatever return $send; @@ -239,13 +245,19 @@ class Main { $string = strip_tags($string); // If set also make the string lowercase - if($lower) + if($lower){ + $string = strtolower($string); + } + // If set remove all characters that aren't a-z or 0-9 - if($nospecial) + if($nospecial) { + $string = preg_replace('/[^a-z0-9]/', '', $string); + } + // Return clean string return $string; @@ -265,9 +277,12 @@ class Main { $newsPosts[$newsId]['rdata'] = Users::getRank($newsPosts[$newsId]['udata']['rank_main']); // Check if a custom name colour is set and if so overwrite the rank colour - if($newsPosts[$newsId]['udata']['name_colour'] != null) + if($newsPosts[$newsId]['udata']['name_colour'] != null){ + $newsPosts[$newsId]['rdata']['colour'] = $newsPosts[$newsId]['udata']['name_colour']; + } + } // Return posts @@ -307,13 +322,19 @@ class Main { if(filter_var($ip, FILTER_VALIDATE_IP)) { // IPv4 - if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) + if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { + return 4; + } + // IPv6 - if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) + if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + return 6; + } + } // Not an IP or unknown type @@ -334,9 +355,12 @@ class Main { $binaryIP = null; // "Build" binary IP - foreach($unpacked as $char) + foreach($unpacked as $char) { + $binaryIP .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT); + } + // Return IP return $binaryIP; @@ -406,9 +430,12 @@ class Main { foreach($cfhosts as $subnet) { // Return true if found - if(self::matchSubnet($ip, $subnet)) + if(self::matchSubnet($ip, $subnet)) { + return true; + } + } // Return false if fails @@ -426,9 +453,12 @@ class Main { if(self::checkCFIP($ip)) { // If it is check if the CloudFlare IP header is set and if it is assign it to the ip variable - if(isset($_SERVER['HTTP_CF_CONNECTING_IP'])) + if(isset($_SERVER['HTTP_CF_CONNECTING_IP'])) { + $ip = $_SERVER['HTTP_CF_CONNECTING_IP']; + } + } // Return the correct IP @@ -440,9 +470,12 @@ class Main { public static function getCountryCode() { // Check if the required header is set and return it - if(isset($_SERVER['HTTP_CF_IPCOUNTRY'])) + if(isset($_SERVER['HTTP_CF_IPCOUNTRY'])) { + return $_SERVER['HTTP_CF_IPCOUNTRY']; + } + // Return XX as a fallback return 'XX'; @@ -452,9 +485,12 @@ class Main { public static function newActionCode($action, $userid, $instruct) { // Make sure the user we're working with exists - if(Users::getUser($userid)['id'] == 0) + if(Users::getUser($userid)['id'] == 0) { + return false; + } + // Convert the instruction array to a JSON $instruct = json_encode($instruct); @@ -484,15 +520,21 @@ class Main { ]); // Check if the code exists - if(count($keyRow) <= 1) + if(count($keyRow) <= 1) { + return [0, 'INVALID_CODE']; + } + // Check if the code was intended for the user that's using this code if($keyRow['userid'] != 0) { - if($keyRow['userid'] != $uid) + if($keyRow['userid'] != $uid) { + return [0, 'INVALID_USER']; + } + } // Remove the key from the database @@ -523,11 +565,16 @@ class Main { $iso3166 = json_decode(utf8_encode(file_get_contents(ROOT .'_sakura/'. Configuration::getLocalConfig('data', 'iso3166'))), true); // Check if key exists - if(array_key_exists($code, $iso3166)) + if(array_key_exists($code, $iso3166)) { + return $iso3166[$code]; // If entry found return the full name - else + + } else { + return 'Unknown'; // Else return unknown + } + } // Get FAQ data @@ -548,9 +595,12 @@ class Main { $return = Database::fetch('logtypes', false, ['id' => [$type, '=']]); // Check if type exists and else return a unformattable string - if(count($return) < 2) + if(count($return) < 2) { + return 'Unknown action.'; + } + // Return the string return $return['string']; diff --git a/_sakura/components/Permissions.php b/_sakura/components/Permissions.php index bac6877..f127a89 100644 --- a/_sakura/components/Permissions.php +++ b/_sakura/components/Permissions.php @@ -66,8 +66,7 @@ class Permissions { // Site management permissions 'MANAGE' => [ - 'USE_MANAGE' => 1, - 'EDIT_INFO_PAGES' => 2 + 'USE_MANAGE' => 1 ] @@ -77,19 +76,30 @@ class Permissions { public static function check($layer, $action, $operator, $mode = 0) { // Check if the permission layer and the permission itself exists - if(!array_key_exists($layer, self::$permissions) || !array_key_exists($action, self::$permissions[$layer])) + if(!array_key_exists($layer, self::$permissions) || !array_key_exists($action, self::$permissions[$layer])) { + return false; + } + // Convert to the appropiate mode - if($mode === 2) + if($mode === 2) { + $operator = self::getRankPermissions($operator)[$layer]; - elseif($mode === 1) + + } elseif($mode === 1) { + $operator = self::getUserPermissions($operator)[$layer]; + } + // Perform the bitwise AND - if(bindec($operator) & self::$permissions[$layer][$action]) + if(bindec($operator) & self::$permissions[$layer][$action]) { + return true; + } + // Else just return false return false; @@ -103,13 +113,19 @@ class Permissions { $perms = []; // Get permission row for all ranks - foreach($ranks as $rank) + foreach($ranks as $rank) { + $getRanks[] = Database::fetch('permissions', false, ['rid' => [$rank, '='], 'uid' => [0 ,'=']]); + } + // Check if getRanks is empty or if the rank id is 0 return the fallback - if(empty($getRanks) || in_array(0, $ranks)) + if(empty($getRanks) || in_array(0, $ranks)) { + $getRanks = [self::$fallback]; + } + // Go over the permission data foreach($getRanks as $rank) { @@ -158,24 +174,36 @@ class Permissions { $rankPerms = self::getRankPermissions(json_decode($user['ranks'], true)); // Just return the rank permissions if no special ones are set - if(empty($userPerms)) + if(empty($userPerms)) { + return $rankPerms; + } + // Split the inherit option things up $inheritance = str_split($userPerms['rankinherit']); // Override site permissions - if(!$inheritance[0]) + if(!$inheritance[0]) { + $rankPerms['SITE'] = $userPerms['siteperms']; + } + // Override management permissions - if(!$inheritance[1]) + if(!$inheritance[1]) { + $rankPerms['MANAGE'] = $userPerms['manageperms']; + } + // Override forum permissions - if(!$inheritance[2]) + if(!$inheritance[2]) { + $rankPerms['FORUM'] = $userPerms['forumperms']; + } + // Return permissions return $rankPerms; diff --git a/_sakura/components/Sessions.php b/_sakura/components/Sessions.php index f10a7b3..5a4c919 100644 --- a/_sakura/components/Sessions.php +++ b/_sakura/components/Sessions.php @@ -53,11 +53,16 @@ class Session { $session = Database::fetch('sessions', true, ['userid' => [$userId, '='], 'skey' => [$sessionId, '=']]); // Check if we actually got something in return - if(!count($session)) + if(!count($session)) { + return false; - else + + } else { + $session = $session[0]; + } + // Check if the session expired if($session['expire'] < time()) { @@ -69,10 +74,52 @@ class Session { } + // Origin checking + if($ipCheck = Configuration::getConfig('session_check')) { + + // Split both IPs up + $sessionIP = explode('.', $session['userip']); + $userIP = explode('.', Main::getRemoteIP()); + + // Take 1 off the ipCheck variable so it's equal to the array keys + $ipCheck = $ipCheck - 1; + + // Check if the user's IP is similar to the session's registered IP + switch($ipCheck) { + + // 000.xxx.xxx.xxx + case 3: + if($userIP[3] !== $sessionIP[3]) return false; + + // xxx.000.xxx.xxx + case 2: + case 3: + if($userIP[2] !== $sessionIP[2]) return false; + + // xxx.xxx.000.xxx + case 1: + case 2: + case 3: + if($userIP[1] !== $sessionIP[1]) return false; + + // xxx.xxx.xxx.000 + case 0: + case 1: + case 2: + case 3: + if($userIP[0] !== $sessionIP[0]) return false; + + } + + } + // If the remember flag is set extend the session time - if($session['remember']) + if($session['remember']) { + Database::update('sessions', [['expire' => time() + 604800], ['id' => [$session['id'], '=']]]); + } + // Return 2 if the remember flag is set and return 1 if not return $session['remember'] ? 2 : 1; @@ -82,9 +129,12 @@ class Session { public static function deleteSession($sessionId, $key = false) { // Check if the session exists - if(!Database::fetch('sessions', [($key ? 'skey' : 'id'), true, [$sessionId, '=']])) + if(!Database::fetch('sessions', [($key ? 'skey' : 'id'), true, [$sessionId, '=']])) { + return false; + } + // Run the query Database::delete('sessions', [($key ? 'skey' : 'id') => [$sessionId, '=']]); diff --git a/_sakura/components/SockChat.php b/_sakura/components/SockChat.php deleted file mode 100644 index 61629f0..0000000 --- a/_sakura/components/SockChat.php +++ /dev/null @@ -1,128 +0,0 @@ - $perm) - $perms[$id]['perms'] = self::decodePerms($perm['perms']); - - // Return the permission data - return $perms; - - } - - // Get permission data for a specific rank - public static function getRankPermissions($rid) { - - // Get data by rank id from permissions table - $perms = Database::fetch('sock_perms', false, ['rid' => [$rid, '='], 'uid' => [0, '=']]); - - // Check if we got a row back - if(empty($perms)) { - $perms = [ - 'rid' => 0, - 'uid' => 0, - 'perms' => self::$_PERMS_FALLBACK - ]; - } - - // Parse permission string - $perms = self::decodePerms($perms['perms']); - - // Return the permission data - return $perms; - - } - - // Get all rank permission data - public static function getUserPermissions($uid) { - - // Get data by user id from permissions table - $perms = Database::fetch('sock_perms', false, ['uid' => [$uid, '='], 'rid' => [0, '=']]); - - // Check if we got a row back - if(empty($perms)) { - - // If we didn't get the user's rank account row - $user = Users::getUser($uid); - - // Then return the data for their rank - return self::getRankPermissions($user['rank_main']); - - } - - // Parse permission string - $perms = self::decodePerms($perms['perms']); - - // Return the permission data - return $perms; - - } - - // Decode permission string - public static function decodePerms($perms) { - - // Explode the commas - $exploded = is_array($perms) ? $perms : explode(',', $perms); - - // "Reset" $perms - $perms = array(); - - // Put the data in the correct order - $perms['access'] = $exploded[ self::$_PERMS_ACCESS_INDEX ]; - $perms['rank'] = $exploded[ self::$_PERMS_RANK_INDEX ]; - $perms['type'] = $exploded[ self::$_PERMS_TYPE_INDEX ]; - $perms['logs'] = $exploded[ self::$_PERMS_LOGS_INDEX ]; - $perms['nick'] = $exploded[ self::$_PERMS_NICK_INDEX ]; - $perms['channel'] = $exploded[ self::$_PERMS_CHANNEL_INDEX ]; - - // Return formatted permissions array - return $perms; - - } - - // Encode permission string - public static function encodePerms($perms) { - - // Create array - $encoded = array(); - - // Put the data in the correct order - $encoded[ self::$_PERMS_ACCESS_INDEX ] = empty($perms['access']) ? 0 : $perms['access']; - $encoded[ self::$_PERMS_RANK_INDEX ] = empty($perms['rank']) ? 0 : $perms['rank']; - $encoded[ self::$_PERMS_TYPE_INDEX ] = empty($perms['type']) ? 0 : $perms['type']; - $encoded[ self::$_PERMS_LOGS_INDEX ] = empty($perms['logs']) ? 0 : $perms['logs']; - $encoded[ self::$_PERMS_NICK_INDEX ] = empty($perms['nick']) ? 0 : $perms['nick']; - $encoded[ self::$_PERMS_CHANNEL_INDEX ] = empty($perms['channel']) ? 0 : $perms['channel']; - - // Implode the array - $perms = implode(',', $encoded); - - // Return formatted permissions array - return $perms; - - } - -} diff --git a/_sakura/components/Urls.php b/_sakura/components/Urls.php index 8f20099..5a2f0de 100644 --- a/_sakura/components/Urls.php +++ b/_sakura/components/Urls.php @@ -11,20 +11,34 @@ class Urls { protected $urls = [ // General site sections - 'SITE_HOME' => ['/', '/'], - 'SITE_NEWS' => ['/news.php', '/news'], - 'SITE_NEWS_PAGE' => ['/news.php?page=%u', '/news/p%u'], - 'SITE_NEWS_POST' => ['/news.php?id=%u', '/news/%u'], - 'SITE_NEWS_RSS' => ['/news.php?xml=true', '/news.xml'], - 'SITE_SEARCH' => ['/search.php', '/search'], - 'SITE_MEMBERS' => ['/members.php', '/members'], - 'SITE_PREMIUM' => ['/support.php', '/support'], - 'SITE_FAQ' => ['/faq.php', '/faq'], - 'SITE_LOGIN' => ['/authenticate.php', '/login'], - 'SITE_REGISTER' => ['/authenticate.php', '/register'], - 'CHANGELOG' => ['/changelog.php', '/changelog'], - 'INFO_PAGE' => ['/index.php?p=%s', '/p/%s'], - 'AUTH_ACTION' => ['/authenticate.php', '/authenticate'], + 'SITE_HOME' => ['/', '/'], + 'SITE_NEWS' => ['/news.php', '/news'], + 'SITE_NEWS_PAGE' => ['/news.php?page=%u', '/news/p%u'], + 'SITE_NEWS_POST' => ['/news.php?id=%u', '/news/%u'], + 'SITE_NEWS_RSS' => ['/news.php?xml=true', '/news.xml'], + 'SITE_SEARCH' => ['/search.php', '/search'], + 'SITE_PREMIUM' => ['/support.php', '/support'], + 'SITE_DONATE_TRACK' => ['/support.php?tracker=true', '/support/tracker'], + 'SITE_DONATE_TRACK_PAGE' => ['/support.php?tracker=true&page=%u', '/support/tracker/%u'], + 'SITE_FAQ' => ['/faq.php', '/faq'], + 'SITE_LOGIN' => ['/authenticate.php', '/login'], + 'SITE_LOGOUT' => ['/authenticate.php', '/logout'], + 'SITE_REGISTER' => ['/authenticate.php', '/register'], + 'SITE_FORGOT_PASSWORD' => ['/authenticate.php', '/forgotpassword'], + 'SITE_ACTIVATE' => ['/authenticate.php', '/activate'], + 'CHANGELOG' => ['/changelog.php', '/changelog'], + 'INFO_PAGE' => ['/index.php?p=%s', '/p/%s'], + 'AUTH_ACTION' => ['/authenticate.php', '/authenticate'], + + // Memberlist + 'MEMBERLIST_INDEX' => ['/members.php', '/members'], + 'MEMBERLIST_SORT' => ['/members.php?sort=%s', '/members/%s'], + 'MEMBERLIST_RANK' => ['/members.php?rank=%u', '/members/%u'], + 'MEMBERLIST_PAGE' => ['/members.php?page=%u', '/members/p%u'], + 'MEMBERLIST_SORT_RANK' => ['/members.php?sort=%s&rank=%u', '/members/%s/%u'], + 'MEMBERLIST_RANK_PAGE' => ['/members.php?rank=%u&page=%u', '/members/%u/p%u'], + 'MEMBERLIST_SORT_PAGE' => ['/members.php?sort=%s&page=%u', '/members/%s/p%u'], + 'MEMBERLIST_ALL' => ['/members.php?sort=%s&rank=%u&page=%u', '/members/%s/%u/p%u'], // Forums 'FORUM_INDEX' => ['/index.php?forum=true', '/forum'], @@ -44,8 +58,9 @@ class Urls { // User actions 'USER_LOGOUT' => ['/authenticate.php?mode=logout&time=%u&session=%s&redirect=%s', '/logout?mode=logout&time=%u&session=%s&redirect=%s'], - 'USER_PROFILE' => ['/profile.php?u=%s', '/u/%s'], 'USER_REPORT' => ['/report.php?mode=user&u=%u', '/u/%u/report'], + 'USER_PROFILE' => ['/profile.php?u=%s', '/u/%s'], + 'USER_GROUP' => ['/group.php?g=%u', '/g/%u'], // Settings urls 'SETTINGS_INDEX' => ['/settings.php', '/settings'], @@ -60,7 +75,9 @@ class Urls { 'FRIEND_REMOVE' => ['/settings.php?friend-action=true&remove=%u&session=%s&time=%u&redirect=%s', '/friends?remove=%u&session=%s&time=%u&redirect=%s'], // Manage urls - 'MANAGE_INDEX' => ['/manage.php', '/manage'] + 'MANAGE_INDEX' => ['/manage.php', '/manage'], + 'MANAGE_CAT' => ['/manage.php?cat=%s', '/manage/%s'], + 'MANAGE_MODE' => ['/manage.php?cat=%s&mode=%s', '/manage/%s/%s'] ]; diff --git a/_sakura/components/Users.php b/_sakura/components/Users.php index ccc1eca..7d40c91 100644 --- a/_sakura/components/Users.php +++ b/_sakura/components/Users.php @@ -64,19 +64,28 @@ class Users { if(!$bypassCookies) { // Check if the cookies are set - if(!isset($_COOKIE[Configuration::getConfig('cookie_prefix') .'id']) || !isset($_COOKIE[Configuration::getConfig('cookie_prefix') .'session'])) + if(!isset($_COOKIE[Configuration::getConfig('cookie_prefix') .'id']) || !isset($_COOKIE[Configuration::getConfig('cookie_prefix') .'session'])) { + return false; + } + } // Check if the session exists - if(!$session = Session::checkSession($uid, $sid)) + if(!$session = Session::checkSession($uid, $sid)) { + return false; + } + // Check if the user is activated - if(Permissions::check('SITE', 'DEACTIVATED', $uid, 1)) + if(Permissions::check('SITE', 'DEACTIVATED', $uid, 1)) { + return false; + } + // Extend the cookie times if the remember flag is set if($session == 2 && !$bypassCookies) { @@ -107,13 +116,19 @@ class Users { public static function login($username, $password, $remember = false, $cookies = true) { // Check if authentication is disallowed - if(Configuration::getConfig('lock_authentication')) + if(Configuration::getConfig('lock_authentication')) { + return [0, 'AUTH_LOCKED']; + } + // Check if the user that's trying to log in actually exists - if(!$uid = self::userExists($username, false)) + if(!$uid = self::userExists($username, false)) { + return [0, 'USER_NOT_EXIST']; + } + // Get account data $user = self::getUser($uid); @@ -140,9 +155,12 @@ class Users { } // Check if the user has the required privs to log in - if(Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) + if(Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) { + return [0, 'NOT_ALLOWED']; + } + // Create a new session $sessionKey = Session::newSession($user['id'], $remember); @@ -155,7 +173,7 @@ class Users { } // Successful login! (also has a thing for the legacy password system) - return [1, ($user['password_algo'] == 'legacy' ? 'LEGACY_SUCCESS' : 'LOGIN_SUCESS')]; + return [1, 'LOGIN_SUCESS']; } @@ -163,13 +181,19 @@ class Users { public static function logout() { // Check if user is logged in - if(!self::checkLogin()) + if(!self::checkLogin()) { + return false; + } + // Remove the active session from the database - if(!Session::deleteSession(Session::$sessionId, true)) + if(!Session::deleteSession(Session::$sessionId, true)) { + return false; + } + // Set cookies setcookie(Configuration::getConfig('cookie_prefix') .'id', 0, time() - 60, Configuration::getConfig('cookie_path'), Configuration::getConfig('cookie_domain')); setcookie(Configuration::getConfig('cookie_prefix') .'session', '', time() - 60, Configuration::getConfig('cookie_path'), Configuration::getConfig('cookie_domain')); @@ -183,62 +207,98 @@ class Users { public static function register($username, $password, $confirmpass, $email, $tos, $captcha = null, $regkey = null) { // Check if authentication is disallowed - if(Configuration::getConfig('lock_authentication')) + if(Configuration::getConfig('lock_authentication')) { + return [0, 'AUTH_LOCKED']; + } + // Check if registration is even enabled - if(Configuration::getConfig('disable_registration')) + if(Configuration::getConfig('disable_registration')) { + return [0, 'DISABLED']; + } + // Check if registration codes are required if(Configuration::getConfig('require_registration_code')) { // Check if the code is valid - if(!self::checkRegistrationCode($regkey)) + if(!self::checkRegistrationCode($regkey)) { + return [0, 'INVALID_REG_KEY']; + } + } // Check if the user agreed to the ToS - if(!$tos) + if(!$tos) { + return [0, 'TOS']; + } + // Verify the captcha if it's enabled if(Configuration::getConfig('recaptcha')) { - if(!Main::verifyCaptcha($captcha)['success']) + if(!Main::verifyCaptcha($captcha)['success']) { + return [0, 'CAPTCHA_FAIL']; + } + } // Check if the username already exists - if(self::userExists($username, false)) + if(self::userExists($username, false)) { + return [0, 'USER_EXISTS']; + } + // Username too short - if(strlen($username) < Configuration::getConfig('username_min_length')) + if(strlen($username) < Configuration::getConfig('username_min_length')) { + return [0, 'NAME_TOO_SHORT']; + } + // Username too long - if(strlen($username) > Configuration::getConfig('username_max_length')) + if(strlen($username) > Configuration::getConfig('username_max_length')) { + return [0, 'NAME_TOO_LONG']; + } + // Check if the given email address is formatted properly - if(!filter_var($email, FILTER_VALIDATE_EMAIL)) + if(!filter_var($email, FILTER_VALIDATE_EMAIL)) { + return [0, 'INVALID_EMAIL']; + } + // Check the MX record of the email - if(!Main::checkMXRecord($email)) + if(!Main::checkMXRecord($email)) { + return [0, 'INVALID_MX']; + } + // Check password entropy - if(Main::pwdEntropy($password) < Configuration::getConfig('min_entropy')) + if(Main::pwdEntropy($password) < Configuration::getConfig('min_entropy')) { + return [0, 'PASS_TOO_SHIT']; + } + // Passwords do not match - if($password != $confirmpass) + if($password != $confirmpass) { + return [0, 'PASS_NOT_MATCH']; + } + // Set a few variables $usernameClean = Main::cleanString($username, true); $emailClean = Main::cleanString($email, true); @@ -295,9 +355,12 @@ class Users { public static function sendPasswordForgot($username, $email) { // Check if authentication is disallowed - if(Configuration::getConfig('lock_authentication')) + if(Configuration::getConfig('lock_authentication')) { + return [0, 'AUTH_LOCKED']; + } + // Clean username string $usernameClean = Main::cleanString($username, true); $emailClean = Main::cleanString($email, true); @@ -309,13 +372,19 @@ class Users { ]); // Check if user exists - if(count($user) < 2) + if(count($user) < 2) { + return [0, 'USER_NOT_EXIST']; + } + // Check if the user has the required privs to log in - if(Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) + if(Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) { + return [0, 'NOT_ALLOWED']; + } + // Generate the verification key $verk = Main::newActionCode('LOST_PASS', $user['id'], [ 'meta' => [ @@ -323,13 +392,16 @@ class Users { ] ]); + // Create new urls object + $urls = new Urls(); + // Build the e-mail $message = "Hello ". $user['username'] .",\r\n\r\n"; $message .= "You are receiving this notification because you have (or someone pretending to be you has) requested a password reset link to be sent for your account on \"". Configuration::getConfig('sitename') ."\". If you did not request this notification then please ignore it, if you keep receiving it please contact the site administrator.\r\n\r\n"; $message .= "To use this password reset key you need to go to a special page. To do this click the link provided below.\r\n\r\n"; - $message .= "http://". Configuration::getConfig('url_main') ."/forgotpassword?pw=true&uid=". $user['id'] ."&key=". $verk ."\r\n\r\n"; + $message .= "http://". Configuration::getConfig('url_main') . $urls->format('SITE_FORGOT_PASSWORD') ."?pw=true&uid=". $user['id'] ."&key=". $verk ."\r\n\r\n"; $message .= "If successful you should be able to change your password here.\r\n\r\n"; - $message .= "Alternatively if the above method fails for some reason you can go to http://". Configuration::getConfig('url_main') ."/forgotpassword?pw=true&uid=". $user['id'] ." and use the key listed below:\r\n\r\n"; + $message .= "Alternatively if the above method fails for some reason you can go to http://". Configuration::getConfig('url_main') . $urls->format('SITE_FORGOT_PASSWORD') ."?pw=true&uid=". $user['id'] ." and use the key listed below:\r\n\r\n"; $message .= "Verification key: ". $verk ."\r\n\r\n"; $message .= "You can of course change this password yourself via the profile page. If you have any difficulties please contact the site administrator.\r\n\r\n"; $message .= "--\r\n\r\nThanks\r\n\r\n". Configuration::getConfig('mail_signature'); @@ -346,24 +418,36 @@ class Users { public static function resetPassword($verk, $uid, $newpass, $verpass) { // Check if authentication is disallowed - if(Configuration::getConfig('lock_authentication')) + if(Configuration::getConfig('lock_authentication')) { + return [0, 'AUTH_LOCKED']; + } + // Check password entropy - if(Main::pwdEntropy($newpass) < Configuration::getConfig('min_entropy')) + if(Main::pwdEntropy($newpass) < Configuration::getConfig('min_entropy')) { + return [0, 'PASS_TOO_SHIT']; + } + // Passwords do not match - if($newpass != $verpass) + if($newpass != $verpass) { + return [0, 'PASS_NOT_MATCH']; + } + // Check the verification key $action = Main::useActionCode('LOST_PASS', $verk, $uid); // Check if we got a negative return - if(!$action[0]) + if(!$action[0]) { + return [0, $action[1]]; + } + // Hash the password $password = Hashing::create_hash($newpass); $time = time(); @@ -391,9 +475,12 @@ class Users { public static function resendActivationMail($username, $email) { // Check if authentication is disallowed - if(Configuration::getConfig('lock_authentication')) + if(Configuration::getConfig('lock_authentication')) { + return [0, 'AUTH_LOCKED']; + } + // Clean username string $usernameClean = Main::cleanString($username, true); $emailClean = Main::cleanString($email, true); @@ -405,13 +492,19 @@ class Users { ]); // Check if user exists - if(count($user) < 2) + if(count($user) < 2) { + return [0, 'USER_NOT_EXIST']; + } + // Check if a user is activated - if(!Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) + if(!Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) { + return [0, 'USER_ALREADY_ACTIVE']; + } + // Send activation e-mail self::sendActivationMail($user['id']); @@ -427,9 +520,12 @@ class Users { $user = Database::fetch('users', false, ['id' => [$uid, '=']]); // User is already activated or doesn't even exist - if(count($user) < 2 || !Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) + if(count($user) < 2 || !Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) { + return false; + } + // Generate activation key $activate = ($customKey ? $customKey : Main::newActionCode('ACTIVATE', $uid, [ 'user' => [ @@ -438,15 +534,18 @@ class Users { ] ])); + // Create new urls object + $urls = new Urls(); + // Build the e-mail $message = "Welcome to ". Configuration::getConfig('sitename') ."!\r\n\r\n"; $message .= "Please keep this e-mail for your records. Your account intormation is as follows:\r\n\r\n"; $message .= "----------------------------\r\n\r\n"; $message .= "Username: ". $user['username'] ."\r\n\r\n"; - $message .= "Your profile: http://". Configuration::getConfig('url_main') ."/u/". $user['id'] ."\r\n\r\n"; + $message .= "Your profile: http://". Configuration::getConfig('url_main') . $urls->format('USER_PROFILE', [$user['id']]) ."\r\n\r\n"; $message .= "----------------------------\r\n\r\n"; $message .= "Please visit the following link in order to activate your account:\r\n\r\n"; - $message .= "http://". Configuration::getConfig('url_main') ."/activate?mode=activate&u=". $user['id'] ."&k=". $activate ."\r\n\r\n"; + $message .= "http://". Configuration::getConfig('url_main') . $urls->format('SITE_ACTIVATE') ."?mode=activate&u=". $user['id'] ."&k=". $activate ."\r\n\r\n"; $message .= "Your password has been securely stored in our database and cannot be retrieved. "; $message .= "In the event that it is forgotten, you will be able to reset it using the email address associated with your account.\r\n\r\n"; $message .= "Thank you for registering.\r\n\r\n"; @@ -467,13 +566,19 @@ class Users { $user = Database::fetch('users', false, ['id' => [$uid, '=']]); // Check if user exists - if(!count($user) > 1) + if(!count($user) > 1) { + return [0, 'USER_NOT_EXIST']; + } + // Check if user is already activated - if(!Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) + if(!Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) { + return [0, 'USER_ALREADY_ACTIVE']; + } + // Set default values for activation $rank = 2; $ranks = json_encode([2]); @@ -485,9 +590,12 @@ class Users { $action = Main::useActionCode('ACTIVATE', $key, $uid); // Check if we got a negative return - if(!$action[0]) + if(!$action[0]) { + return [0, $action[1]]; + } + // Assign the special values $instructionData = json_decode($action[2], true); $rank = $instructionData['user']['rank_main']; @@ -518,13 +626,19 @@ class Users { $user = Database::fetch('users', false, ['id' => [$uid, '=']]); // Check if user exists - if(!count($user) > 1) + if(!count($user) > 1) { + return [0, 'USER_NOT_EXIST']; + } + // Check if user is already deactivated - if(Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) + if(Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) { + return [0, 'USER_ALREADY_DEACTIVE']; + } + // Deactivate the account Database::update('users', [ [ @@ -556,9 +670,12 @@ class Users { public static function markRegistrationCodeUsed($code, $uid = 0) { // Check if the code exists - if(!$id = self::checkRegistrationCode($code)) + if(!$id = self::checkRegistrationCode($code)) { + return false; + } + // Mark it as used Database::update('regcodes', [ [ @@ -579,13 +696,19 @@ class Users { public static function createRegistrationCode() { // Check if we're logged in - if(!self::checkLogin()) + if(!self::checkLogin()) { + return false; + } + // Check if the user is not exceeding the maximum registration key amount - if(count(Database::fetch('regcodes', true, ['uid' => [Session::$userId, '=']])) >= Configuration::getConfig('max_reg_keys')) + if(count(Database::fetch('regcodes', true, ['uid' => [Session::$userId, '=']])) >= Configuration::getConfig('max_reg_keys')) { + return false; + } + // Generate a code by MD5'ing some random bullshit $code = md5('SAKURA'. rand(0, 99999999) . Session::$userId .'NOOKLSISGOD'); @@ -612,9 +735,12 @@ class Users { $ranks = json_decode($user['ranks'], true); // Check if the rank we're trying to set is actually there - if(!in_array($rid, $ranks)) + if(!in_array($rid, $ranks)) { + return false; + } + // Update the row Database::update('users', [ [ @@ -709,9 +835,12 @@ class Users { $user = $userIdIsUserData ? $userid : self::getUser($userid); // Check if the main rank is the specified rank - if(in_array($user['rank_main'], $ranks)) + if(in_array($user['rank_main'], $ranks)) { + return true; + } + // Decode the json for the user's ranks $uRanks = json_decode($user['ranks'], true); @@ -750,9 +879,12 @@ class Users { $profileFields = Database::fetch('profilefields'); // If there's nothing just return null - if(!count($profileFields)) + if(!count($profileFields)) { + return null; + } + // Create output array $fields = []; @@ -811,16 +943,22 @@ class Users { $profileFields = Database::fetch('profilefields'); // If there's nothing just return null - if(!count($profileFields)) + if(!count($profileFields)) { + return null; + } + // Assign the profileData variable $profileData = ($inputIsData ? $id : self::getUser($id)['userData']); // Once again if nothing was returned just return null - if(count($profileData) < 1 || $profileData == null || empty($profileData['profileFields'])) + if(count($profileData) < 1 || $profileData == null || empty($profileData['profileFields'])) { + return null; + } + // Redeclare profileData $profileData = $profileData['profileFields']; @@ -834,9 +972,12 @@ class Users { $fieldName = Main::cleanString($field['name'], true, true); // Check if the user has the current field set otherwise continue - if(!array_key_exists($fieldName, $profileData)) + if(!array_key_exists($fieldName, $profileData)) { + continue; + } + // Assign field to output with value $profile[$fieldName] = array(); $profile[$fieldName]['name'] = $field['name']; @@ -844,9 +985,12 @@ class Users { $profile[$fieldName]['islink'] = $field['islink']; // If the field is set to be a link add a value for that as well - if($field['islink']) + if($field['islink']) { + $profile[$fieldName]['link'] = str_replace('{{ VAL }}', $profileData[$fieldName], $field['linkformat']); + } + // Check if we have additional options as well if($field['additional'] != null) { @@ -857,9 +1001,12 @@ class Users { foreach($additional as $subName => $subField) { // Check if the user has the current field set otherwise continue - if(!array_key_exists($subName, $profileData)) + if(!array_key_exists($subName, $profileData)) { + continue; + } + // Assign field to output with value $profile[$fieldName][$subName] = $profileData[$subName]; @@ -905,9 +1052,12 @@ class Users { $user = self::getUser($id); // Return false if the user doesn't exist because a user that doesn't exist can't be online - if(empty($user)) + if(empty($user)) { + return false; + } + // Return true if the user was online in the last 5 minutes return ($user['lastdate'] > (time() - 500)); @@ -979,18 +1129,24 @@ class Users { public static function checkUserPremium($id) { // Check if the user has static premium - if(Permissions::check('SITE', 'STATIC_PREMIUM', $id, 1)) + if(Permissions::check('SITE', 'STATIC_PREMIUM', $id, 1)) { + return [2, 0, time() + 1]; + } + // Attempt to retrieve the premium record from the database $getRecord = Database::fetch('premium', false, [ 'uid' => [$id, '='] ]); // If nothing was returned just return false - if(empty($getRecord)) + if(empty($getRecord)) { + return [0]; + } + // Check if the Tenshi hasn't expired if($getRecord['expiredate'] < time()) { @@ -1021,9 +1177,12 @@ class Users { self::addRanksToUser([$premiumRank], $id); // Check if the user's default rank is standard user and update it to premium - if(self::getUser($id)['rank_main'] == 2) + if(self::getUser($id)['rank_main'] == 2) { + self::setDefaultRank($id, $premiumRank); + } + } elseif($check[0] == 0 && count($check) > 1) { // Else remove the rank from them @@ -1040,9 +1199,12 @@ class Users { $user = Database::fetch('users', false, ['id' => [$id, '=']]); // Return false if no user was found - if(empty($user)) + if(empty($user)) { + $user = self::$emptyUser; + } + // Parse the json in the additional section $user['userData'] = json_decode($user['userData'], true); @@ -1058,9 +1220,12 @@ class Users { $rank = Database::fetch('ranks', false, ['id' => [$id, '=']]); // Return false if no rank was found - if(empty($rank)) + if(empty($rank)) { + return self::$emptyRank; + } + // If rank was found return rank data return $rank; @@ -1087,9 +1252,12 @@ class Users { public static function getUsersInRank($rankId, $users = null, $excludeAbyss = true) { // Get all users (or use the supplied user list to keep server load down) - if(!$users) + if(!$users) { + $users = self::getAllUsers(); + } + // Make output array $rank = array(); @@ -1097,9 +1265,12 @@ class Users { foreach($users as $user) { // If so store the user's row in the array - if(self::checkIfUserHasRanks([$rankId], $user, true) && ($excludeAbyss ? $user['password_algo'] != 'nologin' : true)) + if(self::checkIfUserHasRanks([$rankId], $user, true) && ($excludeAbyss ? $user['password_algo'] != 'nologin' : true)) { + $rank[] = $user; + } + } // Then return the array with the user rows @@ -1120,13 +1291,19 @@ class Users { foreach($getUsers as $user) { // Skip abyss - if(!$includeAbyss && $user['password_algo'] == 'nologin') + if(!$includeAbyss && $user['password_algo'] == 'nologin') { + continue; + } + // Skip if inactive and not include deactivated users - if(!$includeInactive && Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) + if(!$includeInactive && Permissions::check('SITE', 'DEACTIVATED', $user['id'], 1)) { + continue; + } + $users[$user['id']] = $user; } @@ -1146,9 +1323,12 @@ class Users { $ranks = []; // Reorder shit - foreach($getRanks as $rank) + foreach($getRanks as $rank) { + $ranks[$rank['id']] = $rank; + } + // and return an array with the ranks return $ranks; @@ -1173,11 +1353,19 @@ class Users { // Prepare conditions $conditions = array(); $conditions['uid'] = [($uid ? $uid : Session::$userId), '=']; - if($timediff) + + if($timediff) { + $conditions['timestamp'] = [time() - $timediff, '>']; - if($excludeRead) + + } + + if($excludeRead) { + $conditions['notif_read'] = [0, '=']; + } + // Get notifications for the database $notifications = Database::fetch('notifications', true, $conditions); @@ -1188,9 +1376,12 @@ class Users { foreach($notifications as $notification) { // If the notifcation is already read skip - if($notification['notif_read']) + if($notification['notif_read']) { + continue; + } + // Mark them as read self::markNotificationRead($notification['id']); @@ -1273,9 +1464,12 @@ class Users { public static function getFriends($uid = null, $timestamps = false, $getData = false, $checkOnline = false) { // Assign $uid - if(!$uid) + if(!$uid) { + $uid = Session::$userId; + } + // Get all friends $getFriends = Database::fetch('friends', true, [ 'uid' => [$uid, '='] @@ -1318,9 +1512,12 @@ class Users { public static function getPendingFriends($uid = null, $getData = false) { // Assign $of automatically if it's not set - if(!$uid) + if(!$uid) { + $uid = Session::$userId; + } + // Get all friend entries from other people involved the current user $friends = Database::fetch('friends', true, [ 'fid' => [$uid, '='] @@ -1355,23 +1552,32 @@ class Users { public static function checkFriend($fid, $uid = null) { // Assign $uid - if(!$uid) + if(!$uid) { + $uid = Session::$userId; + } + // Get the user's friends $self = self::getFriends($uid); // Check if the friend is actually in the user's array - if(!in_array($fid, $self)) + if(!in_array($fid, $self)) { + return 0; + } + // Get the friend's friends $friend = self::getFriends($fid); // Check if the friend is actually in the user's array - if(in_array($uid, $friend)) + if(in_array($uid, $friend)) { + return 2; + } + // Return true if all went through return 1; @@ -1381,13 +1587,19 @@ class Users { public static function addFriend($uid) { // Validate that the user exists - if(!self::getUser($uid)) + if(!self::getUser($uid)) { + return [0, 'USER_NOT_EXIST']; + } + // Check if the user already has this user a friend - if(Database::fetch('friends', false, ['fid' => [$uid, '='], 'uid' => [Session::$userId, '=']])) + if(Database::fetch('friends', false, ['fid' => [$uid, '='], 'uid' => [Session::$userId, '=']])) { + return [0, 'ALREADY_FRIENDS']; + } + // Add friend Database::insert('friends', [ 'uid' => Session::$userId, @@ -1404,9 +1616,12 @@ class Users { public static function removeFriend($uid, $deleteRequest = false) { // Check if the user has this user a friend - if(!Database::fetch('friends', false, ['fid' => [$uid, '='], 'uid' => [Session::$userId, '=']])) + if(!Database::fetch('friends', false, ['fid' => [$uid, '='], 'uid' => [Session::$userId, '=']])) { + return [0, 'ALREADY_REMOVED']; + } + // Remove friend Database::delete('friends', [ 'uid' => [Session::$userId, '='], diff --git a/_sakura/sakura.php b/_sakura/sakura.php index a63f51c..72310b5 100644 --- a/_sakura/sakura.php +++ b/_sakura/sakura.php @@ -8,7 +8,7 @@ namespace Sakura; // Define Sakura version -define('SAKURA_VERSION', '20150903'); +define('SAKURA_VERSION', '20150905'); define('SAKURA_VLABEL', 'Eminence'); define('SAKURA_COLOUR', '#6C3082'); define('SAKURA_STABLE', false); @@ -48,7 +48,6 @@ require_once ROOT .'_sakura/components/Manage.php'; require_once ROOT .'_sakura/components/Bans.php'; require_once ROOT .'_sakura/components/Whois.php'; require_once ROOT .'_sakura/components/Payments.php'; -require_once ROOT .'_sakura/components/SockChat.php'; // Include database extensions foreach(glob(ROOT .'_sakura/components/database/*.php') as $driver) { @@ -144,10 +143,7 @@ if(!defined('SAKURA_NO_TPL')) { 'requireActivation' => Configuration::getConfig('require_activation'), 'minPwdEntropy' => Configuration::getConfig('min_entropy'), 'minUsernameLength' => Configuration::getConfig('username_min_length'), - 'maxUsernameLength' => Configuration::getConfig('username_max_length'), - - 'disqus_shortname' => Configuration::getConfig('disqus_shortname'), - 'disqus_api_key' => Configuration::getConfig('disqus_api_key') + 'maxUsernameLength' => Configuration::getConfig('username_max_length') ], @@ -189,7 +185,7 @@ if(!defined('SAKURA_NO_TPL')) { ]); Users::logout(); - print Templates::render('errors/banned.tpl', $renderData); + print Templates::render('main/banned.tpl', $renderData); exit; } diff --git a/_sakura/templates/yuuno/errors/information.tpl b/_sakura/templates/yuuno/errors/information.tpl deleted file mode 100644 index 8946efa..0000000 --- a/_sakura/templates/yuuno/errors/information.tpl +++ /dev/null @@ -1,8 +0,0 @@ -{% include 'global/header.tpl' %} -
-

Information

-
- {{ page.message }} - {% if page.redirect %}
Click here if you aren't being redirected.{% endif %} -
-{% include 'global/footer.tpl' %} diff --git a/_sakura/templates/yuuno/forum/index.tpl b/_sakura/templates/yuuno/forum/index.tpl index eed9a21..62d272b 100644 --- a/_sakura/templates/yuuno/forum/index.tpl +++ b/_sakura/templates/yuuno/forum/index.tpl @@ -1,4 +1,6 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}
{% include 'elements/indexPanel.tpl' %} @@ -9,4 +11,4 @@
-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/forum/posting.tpl b/_sakura/templates/yuuno/forum/posting.tpl index ca4d095..0c3e784 100644 --- a/_sakura/templates/yuuno/forum/posting.tpl +++ b/_sakura/templates/yuuno/forum/posting.tpl @@ -1,4 +1,6 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}
@@ -57,4 +59,4 @@
-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/forum/viewforum.tpl b/_sakura/templates/yuuno/forum/viewforum.tpl index 53f5eaf..40799e9 100644 --- a/_sakura/templates/yuuno/forum/viewforum.tpl +++ b/_sakura/templates/yuuno/forum/viewforum.tpl @@ -1,7 +1,9 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}
{% include 'forum/forum.tpl' %}
-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/forum/viewtopic.tpl b/_sakura/templates/yuuno/forum/viewtopic.tpl index 7bf2350..4f0d7a2 100644 --- a/_sakura/templates/yuuno/forum/viewtopic.tpl +++ b/_sakura/templates/yuuno/forum/viewtopic.tpl @@ -1,4 +1,6 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}
{{ forum.forum.forum_name }} / {{ topic.topic_title }}
@@ -56,4 +58,4 @@ {% include 'forum/forumBtns.tpl' %}
-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/global/footer.tpl b/_sakura/templates/yuuno/global/footer.tpl deleted file mode 100644 index 156a2c2..0000000 --- a/_sakura/templates/yuuno/global/footer.tpl +++ /dev/null @@ -1,41 +0,0 @@ - - {% if not sakura.versionInfo.stable %} -
-
-

Sakura Revision {{ sakura.versionInfo.version }} Development

-
-
- {% endif %} -
- - - - diff --git a/_sakura/templates/yuuno/global/information.tpl b/_sakura/templates/yuuno/global/information.tpl new file mode 100644 index 0000000..ac462b8 --- /dev/null +++ b/_sakura/templates/yuuno/global/information.tpl @@ -0,0 +1,12 @@ +{% extends 'global/master.tpl' %} + +{% block content %} +
+
+

Information

+
+ {{ page.message }} + {% if page.redirect %}
Click here if you aren't being redirected.{% endif %} +
+
+{% endblock %} diff --git a/_sakura/templates/yuuno/global/header.tpl b/_sakura/templates/yuuno/global/master.tpl similarity index 55% rename from _sakura/templates/yuuno/global/header.tpl rename to _sakura/templates/yuuno/global/master.tpl index d71882b..5cbe872 100644 --- a/_sakura/templates/yuuno/global/header.tpl +++ b/_sakura/templates/yuuno/global/master.tpl @@ -10,9 +10,9 @@ - {% if page.redirect %} - - {% endif %} +{% if page.redirect %} + +{% endif %} @@ -27,19 +27,10 @@ +{{ block('meta') }} - {% if page.style %} - - {% endif %} +{{ block('css') }} +{{ block('js') }}
@@ -168,7 +169,7 @@ {% if session.checkLogin %} - + {% endif %}
@@ -182,9 +183,9 @@ {% else %} {% if sakura.lockAuth %} - + {% else %} - + {% endif %} {% endif %} @@ -220,14 +221,60 @@ {% endif %} {% if user.checkPermission('SITE', 'RESTRICTED') %} -
+

Your account is current in restricted mode!

A staff member has set your account to restricted mode most likely due to violation of the rules. While restricted you won't be able to use most public features of the site. If you think this is a mistake please get in touch with one of our staff members.
{% endif %}
+ + diff --git a/_sakura/templates/yuuno/errors/http404.tpl b/_sakura/templates/yuuno/global/notfound.tpl similarity index 100% rename from _sakura/templates/yuuno/errors/http404.tpl rename to _sakura/templates/yuuno/global/notfound.tpl diff --git a/_sakura/templates/yuuno/group/index.tpl b/_sakura/templates/yuuno/group/index.tpl new file mode 100644 index 0000000..384a88a --- /dev/null +++ b/_sakura/templates/yuuno/group/index.tpl @@ -0,0 +1 @@ +{% extends 'global/master.tpl' %} diff --git a/_sakura/templates/yuuno/main/authenticate.tpl b/_sakura/templates/yuuno/main/authenticate.tpl index e55653c..400dc88 100644 --- a/_sakura/templates/yuuno/main/authenticate.tpl +++ b/_sakura/templates/yuuno/main/authenticate.tpl @@ -1,4 +1,6 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %} {% if sakura.lockAuth %}

Authentication is currently disallowed, try again later.

{% else %} @@ -190,4 +192,4 @@
{% endif %} -{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/errors/banned.tpl b/_sakura/templates/yuuno/main/banned.tpl similarity index 94% rename from _sakura/templates/yuuno/errors/banned.tpl rename to _sakura/templates/yuuno/main/banned.tpl index b8e60b1..b6ec147 100644 --- a/_sakura/templates/yuuno/errors/banned.tpl +++ b/_sakura/templates/yuuno/main/banned.tpl @@ -1,4 +1,6 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}
@@ -23,4 +25,4 @@
-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/main/faq.tpl b/_sakura/templates/yuuno/main/faq.tpl index 80f5eea..c20cb00 100644 --- a/_sakura/templates/yuuno/main/faq.tpl +++ b/_sakura/templates/yuuno/main/faq.tpl @@ -1,4 +1,6 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}
@@ -21,4 +23,4 @@
-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/main/forgotpassword.tpl b/_sakura/templates/yuuno/main/forgotpassword.tpl index 93b09d6..d4f5620 100644 --- a/_sakura/templates/yuuno/main/forgotpassword.tpl +++ b/_sakura/templates/yuuno/main/forgotpassword.tpl @@ -1,4 +1,6 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}
Forgot Password
@@ -23,4 +25,4 @@
-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/main/index.tpl b/_sakura/templates/yuuno/main/index.tpl index 4594bed..d36caa1 100644 --- a/_sakura/templates/yuuno/main/index.tpl +++ b/_sakura/templates/yuuno/main/index.tpl @@ -1,4 +1,6 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}
{% include 'elements/indexPanel.tpl' %} @@ -12,4 +14,4 @@
-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/main/infopage.tpl b/_sakura/templates/yuuno/main/infopage.tpl index 4203801..c401a3e 100644 --- a/_sakura/templates/yuuno/main/infopage.tpl +++ b/_sakura/templates/yuuno/main/infopage.tpl @@ -1,5 +1,7 @@ {% include 'global/header.tpl' %}
- {{ page.content|raw }} +
+ {{ page.content|raw }} +
{% include 'global/footer.tpl' %} diff --git a/_sakura/templates/yuuno/main/memberlist.tpl b/_sakura/templates/yuuno/main/memberlist.tpl index 97f2e54..4fd42f5 100644 --- a/_sakura/templates/yuuno/main/memberlist.tpl +++ b/_sakura/templates/yuuno/main/memberlist.tpl @@ -1,4 +1,6 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %} {% if session.checkLogin %}

{% if not page.active %}All members{% else %}{{ page.ranks[page.active].name }}{% if page.ranks[page.active].multi %}s{% endif %}{% endif %}

@@ -7,20 +9,20 @@ {% if page.notfound %}

The requested rank was not found!

@@ -52,10 +54,10 @@ - #{{ count }} + #{{ page.active ? count + 1 : count }} - {{ user.username }} + {{ user.username }} {{ user.regdate|date(sakura.dateFormat) }} @@ -67,7 +69,7 @@ {% if not user.usertitle %}{{ page.ranks[user.rank_main].title }}{% else %}{{ user.usertitle }}{% endif %} - {% if user.country|lower == 'eu' %}?{% else %}{{ user.country }}{% endif %} + {% if user.country|lower == 'eu' %}?{% else %}{{ user.country }}{% endif %} @@ -75,9 +77,9 @@ {% else %} {% for user in page.users[page.page] %} - {# These comment tags are here to prevent the link extending too far + {# These comment tags are here to prevent the link extending too far #}
{# - #}{{ user.username }}{# + #}{{ user.username }}{# #}{# #}{{ user.username }}{# #}{# @@ -90,13 +92,13 @@ {% if page.users|length > 1 %} {% endif %} @@ -104,4 +106,4 @@ {% else %} {% include 'elements/restricted.tpl' %} {% endif %} -{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/main/news.tpl b/_sakura/templates/yuuno/main/news.tpl index aa9bd16..cc3a348 100644 --- a/_sakura/templates/yuuno/main/news.tpl +++ b/_sakura/templates/yuuno/main/news.tpl @@ -1,7 +1,9 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}
-
{% if page.view_post %}{{ newsPosts[0].title }}{% elseif newsPosts|length < 1 %}Post does not exist!{% else %}News {% endif %}
+
{% if page.view_post %}{{ newsPosts[0].title }}{% elseif newsPosts|length < 1 %}Post does not exist!{% else %}News {% endif %}
{% if newsPosts|length >= 1 %} {% if page.view_post %} {% for newsPost in newsPosts %} @@ -16,13 +18,13 @@
@@ -40,4 +42,4 @@ {% endif %}
-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/errors/premiumComplete.tpl b/_sakura/templates/yuuno/main/premiumcomplete.tpl similarity index 82% rename from _sakura/templates/yuuno/errors/premiumComplete.tpl rename to _sakura/templates/yuuno/main/premiumcomplete.tpl index 67d2614..c857cee 100644 --- a/_sakura/templates/yuuno/errors/premiumComplete.tpl +++ b/_sakura/templates/yuuno/main/premiumcomplete.tpl @@ -1,7 +1,9 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}

Thank you for your contribution!

Your Tenshi will expire on {{ page.expiration|date(sakura.dateFormat) }}.

-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/main/report.tpl b/_sakura/templates/yuuno/main/report.tpl new file mode 100644 index 0000000..384a88a --- /dev/null +++ b/_sakura/templates/yuuno/main/report.tpl @@ -0,0 +1 @@ +{% extends 'global/master.tpl' %} diff --git a/_sakura/templates/yuuno/main/search.tpl b/_sakura/templates/yuuno/main/search.tpl index a33e579..03361b5 100644 --- a/_sakura/templates/yuuno/main/search.tpl +++ b/_sakura/templates/yuuno/main/search.tpl @@ -1,4 +1,6 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}
Search
@@ -17,4 +19,4 @@
-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/main/settings.tpl b/_sakura/templates/yuuno/main/settings.tpl index d84b15b..3cffde6 100644 --- a/_sakura/templates/yuuno/main/settings.tpl +++ b/_sakura/templates/yuuno/main/settings.tpl @@ -1,4 +1,6 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %}
{% include 'elements/settingsNav.tpl' %} @@ -16,4 +18,4 @@
-{% include 'global/footer.tpl' %} +{% endblock %} diff --git a/_sakura/templates/yuuno/main/support.tpl b/_sakura/templates/yuuno/main/support.tpl index b5d31b0..e32c60a 100644 --- a/_sakura/templates/yuuno/main/support.tpl +++ b/_sakura/templates/yuuno/main/support.tpl @@ -1,15 +1,17 @@ -{% include 'global/header.tpl' %} +{% extends 'global/master.tpl' %} + +{% block content %} {% if page.fail %} -
-

The payment failed or was cancelled!

-

Something went wrong while processing the transaction, your PayPal account wasn't charged.

-
+
+

The payment failed or was cancelled!

+

Something went wrong while processing the transaction, your PayPal account wasn't charged.

+
{% endif %}
Support {{ sakura.siteName }}

In order to keep the site, its services and improvements on it going I need money but I'm not that big of a fan of asking for money without giving anything special in return thus Tenshi exists. Tenshi is the name for our supporter rank which gives you access to an extra set of features (which are listed further down on this page). With your help we can keep adding new stuff, get new hardware and keep the site awesome!

-

Ever wonder what happens on the financial side of things? View the donation tracker!

+

Ever wonder what happens on the financial side of things? View the donation tracker!

{% if page.current[0] %}
@@ -105,7 +107,7 @@ {% endif %}
{% if session.checkLogin and user.checkPermission('SITE', 'OBTAIN_PREMIUM') %} -