r20150905

Signed-off-by: Flashwave <me@flash.moe>
This commit is contained in:
flash 2015-09-05 18:11:04 +02:00
parent 57542ac936
commit e67be33619
50 changed files with 970 additions and 687 deletions

View file

@ -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

View file

@ -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

View file

@ -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', '<b>$1</b>', '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', '<a href=\"$1\" target=\"_blank\">$2</a>', 'Link', 'Embed a URL. Usage: [url=http://google.com]Link to google![/url]', 0),
(7, '/\\[url\\]([a-zA-Z0-9\\.\\$\\-\\_\\.\\+\\*\\!\\\'\\(\\)\\/\\:\\#]+)\\[\\/url\\]/is', '<a href=\"$1\" target=\"_blank\">$1</a>', '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', '<div class=\"quote\"><div class=\"quotee\">$1 wrote:</div><div class=\"text\">$2</div></div>', 'Quote', 'Quote a user\'s post. Usage: [quote=Flashwave]nookls is pretty[/quote]', 0),
(9, '/\\[quote\\](.+)\\[\\/quote]/is', '<div class=\"quote\"><div class=\"quotee\">Quote:</div><div class=\"text\">$1</div></div>', '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', '<div class=\"quote\"><div class=\"quotee\">Quote:</div><div class=\"text\">$1</div></div>', '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

View file

@ -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"
}
]
}

View file

@ -1,31 +1,31 @@
<?php
/*
* Flashii PBKDF2 Password Hashing
* Sakura PBKDF2 Password Hashing
*
* Based on Password Hashing With PBKDF2 (https://defuse.ca/php-pbkdf2.htm).
* Copyright (c) 2013, Taylor Hornby
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -192,9 +192,12 @@ class Main {
$mail->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'];

View file

@ -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;

View file

@ -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, '=']]);

View file

@ -1,128 +0,0 @@
<?php
/*
* Sock Chat extensions
*/
namespace Sakura;
class SockChat {
// Permission indexes
public static $_PERMS_ACCESS_INDEX = 0;
public static $_PERMS_RANK_INDEX = 1;
public static $_PERMS_TYPE_INDEX = 2;
public static $_PERMS_LOGS_INDEX = 3;
public static $_PERMS_NICK_INDEX = 4;
public static $_PERMS_CHANNEL_INDEX = 5;
// Fallback permission row
public static $_PERMS_FALLBACK = [1, 0, 0, 0, 0, 0];
// Get all permission data
public static function getAllPermissions() {
// Get all data from the permissions table
$perms = Database::fetch('sock_perms');
// Parse permission string
foreach($perms as $id => $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;
}
}

View file

@ -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']
];

View file

@ -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, '='],

View file

@ -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;
}

View file

@ -1,8 +0,0 @@
{% include 'global/header.tpl' %}
<div class="content standalone">
<h1>Information</h1>
<hr class="default" />
{{ page.message }}
{% if page.redirect %}<br /><a href="{{ page.redirect }}" class="default">Click here if you aren't being redirected.</a>{% endif %}
</div>
{% include 'global/footer.tpl' %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content homepage forum">
<div class="content-right content-column">
{% include 'elements/indexPanel.tpl' %}
@ -9,4 +11,4 @@
<div class="clear"></div>
</div>
<script type="text/javascript" src="{{ sakura.resources }}/js/ybabstat.js"></script>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content">
<div class="content-column forum posting">
<form method="post" action="{{ sakura.currentPage }}">
@ -57,4 +59,4 @@
</form>
</div>
</div>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,7 +1,9 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content homepage forum viewforum">
<div class="content-column">
{% include 'forum/forum.tpl' %}
</div>
</div>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content homepage forum viewtopic">
<div class="content-column">
<div class="head">{{ forum.forum.forum_name }} / {{ topic.topic_title }}</div>
@ -56,4 +58,4 @@
{% include 'forum/forumBtns.tpl' %}
</div>
</div>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,41 +0,0 @@
<a id="gotop" class="fa fa-angle-double-up hidden" href="#top"></a>
{% if not sakura.versionInfo.stable %}
<div style="background: repeating-linear-gradient(-45deg, #000, #000 10px, #FF0 10px, #FF0 20px); text-align: center; color: #FFF; box-shadow: 0px 0px 1em #FF0;">
<div style="background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, .9) 10%, rgba(0, 0, 0, .9) 90%, rgba(0, 0, 0, 0) 100%); display: inline-block; padding: 0 40px;">
<h3><a style="color: inherit; text-decoration: none;" href="{{ urls.format('CHANGELOG') }}#r{{ sakura.versionInfo.version }}" target="_blank">Sakura Revision {{ sakura.versionInfo.version }} Development</a></h1>
</div>
</div>
{% endif %}
</div>
<div class="footer">
<div class="ftsections">
<div class="copycentre">&copy; 2013-2015 <a href="//flash.moe/" target="_blank">Flashwave</a>, et al.</div>
<ul class="ftsection">
<li class="fthead">General</li>
<li><a href="{{ urls.format('SITE_HOME') }}" title="Flashii Frontpage">Home</a></li>
<li><a href="{{ urls.format('SITE_NEWS') }}" title="Flashii News &amp; Updates">News</a></li>
<li><a href="{{ urls.format('SITE_SEARCH') }}" title="Do full-site search requests">Search</a></li>
<li><a href="{{ urls.format('INFO_PAGE', ['contact']) }}" title="Contact our Staff">Contact</a></li>
<li><a href="{{ urls.format('CHANGELOG') }}" title="All the changes made to Sakura are listed here">Changelog</a></li>
<li><a href="{{ urls.format('SITE_PREMIUM') }}" title="Get Tenshi and help us pay the bills">Support us</a></li>
</ul>
<ul class="ftsection">
<li class="fthead">Community</li>
<li><a href="{{ urls.format('FORUM_INDEX') }}" title="Read and post on our forums">Forums</a></li>
<li><a href="https://twitter.com/_flashii" target="_blank" title="Follow us on Twitter for news messages that are too short for the news page">Twitter</a></li>
<li><a href="https://youtube.com/user/flashiinet" target="_blank" title="Our YouTube page where stuff barely ever gets uploaded, mainly used to archive community creations">YouTube</a></li>
<li><a href="https://steamcommunity.com/groups/flashiinet" target="_blank" title="Our Steam group, play games with other members on the site">Steam</a></li>
<li><a href="https://bitbucket.org/circlestorm" target="_blank" title="Our Open Source repository thing">BitBucket</a></li>
</ul>
<ul class="ftsection">
<li class="fthead">Information</li>
<li><a href="{{ urls.format('SITE_FAQ') }}" title="Questions that get Asked Frequently but not actually">FAQ</a></li>
<li><a href="{{ urls.format('INFO_PAGE', ['rules']) }}" title="Some Rules and Information kind of summing up the ToS">Rules</a></li>
<li><a href="//fiistat.us" target="_blank" title="Check the status on our Servers and related services">Server Status</a></li>
<li><a href="{{ urls.format('INFO_PAGE', ['terms']) }}" title="Our Terms of Service">Terms of Service</a></li>
</ul>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,12 @@
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content standalone">
<div>
<h1>Information</h1>
<hr class="default" />
{{ page.message }}
{% if page.redirect %}<br /><a href="{{ page.redirect }}" class="default">Click here if you aren't being redirected.</a>{% endif %}
</div>
</div>
{% endblock %}

View file

@ -10,9 +10,9 @@
<meta name="msapplication-TileColor" content="#fbeeff" />
<meta name="msapplication-TileImage" content="/content/images/icons/ms-icon-144x144.png" />
<meta name="theme-color" content="#9475B2" />
{% if page.redirect %}
<meta http-equiv="refresh" content="3; URL={{ page.redirect }}" />
{% endif %}
{% if page.redirect %}
<meta http-equiv="refresh" content="3; URL={{ page.redirect }}" />
{% endif %}
<link rel="apple-touch-icon" sizes="57x57" href="/content/images/icons/apple-icon-57x57.png" />
<link rel="apple-touch-icon" sizes="60x60" href="/content/images/icons/apple-icon-60x60.png" />
<link rel="apple-touch-icon" sizes="72x72" href="/content/images/icons/apple-icon-72x72.png" />
@ -27,19 +27,10 @@
<link rel="icon" type="image/png" sizes="96x96" href="/content/images/icons/favicon-96x96.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/content/images/icons/favicon-16x16.png" />
<link rel="manifest" href="/manifest.json" />
{{ block('meta') }}
<!-- CSS -->
<link rel="stylesheet" type="text/css" href="{{ sakura.resources }}/css/yuuno.css" />
{% if page.style %}
<style type="text/css">
{% for element,properties in page.style %}
{{ element|raw }} {
{% for property,value in properties %}
{{ property|raw }}: {{ value|raw }};
{% endfor %}
}
{% endfor %}
</style>
{% endif %}
{{ block('css') }}
<!-- JS -->
<script type="text/javascript" src="{{ sakura.resources }}/js/yuuno.js"></script>
<script type="text/javascript">
@ -67,45 +58,45 @@
};
// Space for things that need to happen onload
window.addEventListener("load", function() {
// Space for things that need to happen onload
window.addEventListener("load", function() {
// Alter the go to top button
var gotop = document.getElementById('gotop');
gotop.setAttribute('href', 'javascript:void(0);');
gotop.setAttribute('onclick', 'scrollToTop();');
// Alter the go to top button
var gotop = document.getElementById('gotop');
gotop.setAttribute('href', 'javascript:void(0);');
gotop.setAttribute('onclick', 'scrollToTop();');
{% if session.checkLogin %}
// Convert href to object in logout link
prepareAjaxLink('headerLogoutLink', 'submitPost', ', true, "Logging out..."');
// Convert href to object in logout link
prepareAjaxLink('headerLogoutLink', 'submitPost', ', true, "Logging out..."');
{% elseif not sakura.lockAuth and php.self != '/authenticate.php' %}
// Make the header login form dynamic
var headerLoginForm = document.getElementById('headerLoginForm');
var createInput = document.createElement('input');
var submit = headerLoginForm.querySelector('[type="submit"]');
// Make the header login form dynamic
var headerLoginForm = document.getElementById('headerLoginForm');
var createInput = document.createElement('input');
var submit = headerLoginForm.querySelector('[type="submit"]');
createInput.setAttribute('name', 'ajax');
createInput.setAttribute('value', 'true');
createInput.setAttribute('type', 'hidden');
headerLoginForm.appendChild(createInput);
createInput.setAttribute('name', 'ajax');
createInput.setAttribute('value', 'true');
createInput.setAttribute('type', 'hidden');
headerLoginForm.appendChild(createInput);
submit.setAttribute('type', 'button');
submit.setAttribute('onclick', 'submitPost(\''+ headerLoginForm.action +'\', formToObject(\'headerLoginForm\'), true, \'Logging in...\');');
submit.setAttribute('type', 'button');
submit.setAttribute('onclick', 'submitPost(\''+ headerLoginForm.action +'\', formToObject(\'headerLoginForm\'), true, \'Logging in...\');');
{% endif %}
{% if session.checkLogin %}
// Make notification requests (there's a seperate one to make it happen before the first 60 seconds)
notifyRequest('{{ php.sessionid }}');
// Create interval
setInterval(function() {
// Make notification requests (there's a seperate one to make it happen before the first 60 seconds)
notifyRequest('{{ php.sessionid }}');
}, 60000);
// Create interval
setInterval(function() {
notifyRequest('{{ php.sessionid }}');
}, 60000);
{% endif %}
{% if php.self == '/profile.php' and session.checkLogin and user.data.id != profile.user.id %}
// Make friend button dynamic
prepareAjaxLink('profileFriendToggle', 'submitPost', ', true, "{% if profile.friend == 0 %}Adding{% else %}Removing{% endif %} friend..."');
// Make friend button dynamic
prepareAjaxLink('profileFriendToggle', 'submitPost', ', true, "{% if profile.friend == 0 %}Adding{% else %}Removing{% endif %} friend..."');
{% endif %}
{% if php.self == '/viewtopic.php' and session.checkLogin %}
@ -117,42 +108,52 @@
{% endif %}
{% if php.self == '/authenticate.php' and not sakura.lockAuth %}
// AJAX Form Submission
var forms = {
{% if not auth.changingPass %}
"loginForm": 'Logging in...',
{% if not sakura.disableRegistration %}"registerForm": 'Processing registration...',{% endif %}
{% if not sakura.requireActivation %}"resendForm": 'Attempting to resend activation...',{% endif %}
"passwordForm": 'Sending password recovery mail...'
{% else %}
"passwordForm": 'Changing password...'
{% endif %}
};
for(var i in forms) {
var form = document.getElementById(i);
var submit = form.querySelector('[type="submit"]');
// AJAX Form Submission
var forms = {
{% if not auth.changingPass %}
"loginForm": 'Logging in...',
{% if not sakura.disableRegistration %}
"registerForm": 'Processing registration...',
{% endif %}
{% if not sakura.requireActivation %}
"resendForm": 'Attempting to resend activation...',
{% endif %}
"passwordForm": 'Sending password recovery mail...'
{% else %}
"passwordForm": 'Changing password...'
{% endif %}
};
form.setAttribute('onkeydown', 'formEnterCatch(event, \''+ submit.id +'\');');
for(var i in forms) {
var form = document.getElementById(i);
var submit = form.querySelector('[type="submit"]');
submit.setAttribute('href', 'javascript:void(0);');
submit.setAttribute('onclick', 'submitPost(\''+ form.action +'\', formToObject(\''+ i+ '\'), true, \''+ forms[i] +'\', '+ (i == 'registerForm' ? 'true' : 'false') +');');
submit.setAttribute('type', 'button');
form.setAttribute('onkeydown', 'formEnterCatch(event, \''+ submit.id +'\');');
submit.setAttribute('href', 'javascript:void(0);');
submit.setAttribute('onclick', 'submitPost(\''+ form.action +'\', formToObject(\''+ i+ '\'), true, \''+ forms[i] +'\', '+ (i == 'registerForm' ? 'true' : 'false') +');');
submit.setAttribute('type', 'button');
var createInput = document.createElement('input');
createInput.setAttribute('name', 'ajax');
createInput.setAttribute('value', 'true');
createInput.setAttribute('type', 'hidden');
form.appendChild(createInput);
}
var createInput = document.createElement('input');
createInput.setAttribute('name', 'ajax');
createInput.setAttribute('value', 'true');
createInput.setAttribute('type', 'hidden');
form.appendChild(createInput);
}
{% endif %}
{% if php.self == '/profile.php' ? profile.data.userData.profileBackground : (user.checkPermission('SITE', 'CREATE_BACKGROUND') and user.data.userData.userOptions.profileBackgroundSiteWide and user.data.userData.profileBackground) %}
{% if php.self == '/profile.php' ? (profile.data.userData.profileBackground and not profile.data.userData.userOptions.disableProfileParallax) : (user.checkPermission('SITE', 'CREATE_BACKGROUND') and user.data.userData.userOptions.profileBackgroundSiteWide and user.data.userData.profileBackground and not user.data.userData.userOptions.disableProfileParallax) %}
initialiseParallax('userBackground');
{% endif %}
});
});
</script>
{{ block('js') }}
</head>
<body>
<div id="container">
@ -168,7 +169,7 @@
<a class="menu-item fa-list" href="{{ urls.format('FORUM_INDEX') }}" title="Forums"></a>
<a class="menu-item fa-search" href="{{ urls.format('SITE_SEARCH') }}" title="Search"></a>
{% if session.checkLogin %}
<a class="menu-item fa-users" href="{{ urls.format('SITE_MEMBERS') }}" title="Members"></a>
<a class="menu-item fa-users" href="{{ urls.format('MEMBERLIST_INDEX') }}" title="Members"></a>
<a class="menu-item fa-heart" href="{{ urls.format('SITE_PREMIUM') }}" title="Support us"></a>
{% endif %}
</div>
@ -182,9 +183,9 @@
<a class="menu-item fa-sign-out" href="{{ urls.format('USER_LOGOUT', [php.time, php.sessionid, sakura.currentPage]) }}" title="Logout" id="headerLogoutLink"></a>
{% else %}
{% if sakura.lockAuth %}
<div class="menu-item fa-lock" style="padding-left: 10px; padding-right: 10px;" title="Authentication is locked"></div>
<div class="menu-item fa-lock" style="padding-left: 10px; padding-right: 10px;" title="Authentication is locked"></div>
{% else %}
<a class="menu-item fa-sign-in" href="{{ urls.format('SITE_LOGIN') }}" title="Login"></a>
<a class="menu-item fa-sign-in" href="{{ urls.format('SITE_LOGIN') }}" title="Login"></a>
{% endif %}
{% endif %}
</div>
@ -220,14 +221,60 @@
</form>
{% endif %}
{% if user.checkPermission('SITE', 'RESTRICTED') %}
<div class="headerNotify" style="padding-top: 10px; padding-bottom: 10px; background: repeating-linear-gradient(-45deg, #B33, #B33 10px, #B00 10px, #B00 20px); text-align: center; color: #FFF; border: 1px solid #C00; box-shadow: 0px 0px 3px #C00;">
<div class="headerNotify" style="background: repeating-linear-gradient(-45deg, #B33, #B33 10px, #B00 10px, #B00 20px); color: #FFF; border: 1px solid #C00; box-shadow: 0px 0px 3px #C00;">
<h1>Your account is current in <span style="font-width: 700 !important;">restricted mode</span>!</h1>
<div>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 <a href="{{ urls.format('INFO_PAGE', ['contact']) }}" style="color: inherit;">get in touch with one of our staff members</a>.</div>
</div>
{% endif %}
<noscript>
<div class="headerNotify" style="padding-top: 10px; padding-bottom: 10px; background: repeating-linear-gradient(-45deg, #C2AFFE, #C2AFFE 10px, #D3BFFF 10px, #D3BFFF 20px);">
<div class="headerNotify">
<h1>You have JavaScript disabled!</h1>
<p style="padding: 0 10px;">A lot of things on this site require JavaScript to be enabled (e.g. the chat), we try to keep both sides happy but it is highly recommended that you enable it (you'll also have to deal with this message being here if you don't enable it).</p>
</div>
</noscript>
{% block content %}
<h1 class="stylised" style="text-align: center; margin: 2em auto;">{{ php.self }} is now printing!</h1>
{% endblock %}
<a id="gotop" class="fa fa-angle-double-up hidden" href="#top"></a>
{% if not sakura.versionInfo.stable %}
<div style="background: repeating-linear-gradient(-45deg, #000, #000 10px, #FF0 10px, #FF0 20px); text-align: center; color: #FFF; box-shadow: 0px 0px 1em #FF0;">
<div style="background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, .9) 10%, rgba(0, 0, 0, .9) 90%, rgba(0, 0, 0, 0) 100%); display: inline-block; padding: 0 40px;">
<h3><a style="color: inherit; text-decoration: none;" href="{{ urls.format('CHANGELOG') }}#r{{ sakura.versionInfo.version }}" target="_blank">Sakura Revision {{ sakura.versionInfo.version }} Development</a></h1>
</div>
</div>
{% endif %}
</div>
<div class="footer">
<div class="ftsections">
<div class="copycentre">&copy; 2013-2015 <a href="//flash.moe/" target="_blank">Flashwave</a>, <a href="http://circlestorm.net/">et al</a>.</div>
<ul class="ftsection">
<li class="fthead">General</li>
<li><a href="{{ urls.format('SITE_HOME') }}" title="Flashii Frontpage">Home</a></li>
<li><a href="{{ urls.format('SITE_NEWS') }}" title="Flashii News &amp; Updates">News</a></li>
<li><a href="{{ urls.format('SITE_SEARCH') }}" title="Do full-site search requests">Search</a></li>
<li><a href="{{ urls.format('INFO_PAGE', ['contact']) }}" title="Contact our Staff">Contact</a></li>
<li><a href="{{ urls.format('CHANGELOG') }}" title="All the changes made to Sakura are listed here">Changelog</a></li>
<li><a href="{{ urls.format('SITE_PREMIUM') }}" title="Get Tenshi and help us pay the bills">Support us</a></li>
</ul>
<ul class="ftsection">
<li class="fthead">Community</li>
<li><a href="{{ urls.format('FORUM_INDEX') }}" title="Read and post on our forums">Forums</a></li>
<li><a href="https://twitter.com/_flashii" target="_blank" title="Follow us on Twitter for news messages that are too short for the news page">Twitter</a></li>
<li><a href="https://youtube.com/user/flashiinet" target="_blank" title="Our YouTube page where stuff barely ever gets uploaded, mainly used to archive community creations">YouTube</a></li>
<li><a href="https://steamcommunity.com/groups/flashiinet" target="_blank" title="Our Steam group, play games with other members on the site">Steam</a></li>
<li><a href="https://bitbucket.org/circlestorm" target="_blank" title="Our Open Source repository thing">BitBucket</a></li>
</ul>
<ul class="ftsection">
<li class="fthead">Information</li>
<li><a href="{{ urls.format('SITE_FAQ') }}" title="Questions that get Asked Frequently but not actually">FAQ</a></li>
<li><a href="{{ urls.format('INFO_PAGE', ['rules']) }}" title="Some Rules and Information kind of summing up the ToS">Rules</a></li>
<li><a href="//fiistat.us" target="_blank" title="Check the status on our Servers and related services">Server Status</a></li>
<li><a href="{{ urls.format('INFO_PAGE', ['terms']) }}" title="Our Terms of Service">Terms of Service</a></li>
</ul>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1 @@
{% extends 'global/master.tpl' %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
{% if sakura.lockAuth %}
<h1 class="stylised" style="line-height: 1.8em; text-align: center;">Authentication is currently disallowed, try again later.</h1>
{% else %}
@ -190,4 +192,4 @@
<div class="clear"></div>
</div>
{% endif %}
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content">
<div class="content-column news banned">
<div style="padding: 20px;">
@ -23,4 +25,4 @@
</div>
</div>
</div>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content settings">
<div class="content-right content-column">
<div class="head">
@ -21,4 +23,4 @@
</div>
<div class="clear"></div>
</div>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content news settings">
<div class="head">Forgot Password</div>
<form method="post" action="{{ urls.format('AUTH_ACTION') }}" id="passwordForm">
@ -23,4 +25,4 @@
</div>
</form>
</div>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content homepage">
<div class="content-right content-column">
{% include 'elements/indexPanel.tpl' %}
@ -12,4 +14,4 @@
<div class="clear"></div>
</div>
<script type="text/javascript" src="{{ sakura.resources }}/js/ybabstat.js"></script>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,5 +1,7 @@
{% include 'global/header.tpl' %}
<div class="content standalone markdown">
{{ page.content|raw }}
<div>
{{ page.content|raw }}
</div>
</div>
{% include 'global/footer.tpl' %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
{% if session.checkLogin %}
<div class="headerNotify" style="padding: 10px 0; margin-bottom: 1px;">
<h1 style="text-shadow: 0px 0px 5px #555;{% if page.active %} color: {{ page.ranks[page.active].colour }};{% endif %}">{% if not page.active %}All members{% else %}{{ page.ranks[page.active].name }}{% if page.ranks[page.active].multi %}s{% endif %}{% endif %}</h1>
@ -7,20 +9,20 @@
<div class="membersPage" style="min-height: 500px;">
<div class="dropDown" style="margin: 0px auto; font-size: 1.5em; line-height: 1.5em; height: 30px;">
<div class="dropDownInner" style="float: left; color: #FFF;">
<a class="dropDownDesc">Rank:</a><!--
--><a href="/members/{% if page.sort != page.sorts[0] %}{{ page.sort }}/{% endif %}"{% if not page.active %} class="dropDownSelected"{% endif %}>All members</a><!--
<a class="dropDownDesc">Rank:</a>
<a href="{% if page.page and page.sort %}{{ urls.format('MEMBERLIST_SORT_PAGE', [page.sort, (page.page + 1)]) }}{% elseif page.sort %}{{ urls.format('MEMBERLIST_SORT', [page.sort]) }}{% elseif page.page %}{{ urls.format('MEMBERLIST_PAGE', [(page.page + 1)]) }}{% else %}{{ urls.format('MEMBERLIST_INDEX') }}{% endif %}"{% if not page.active %} class="dropDownSelected"{% endif %}>All members</a>
{% for rank in page.ranks %}
{% if not rank.hidden or (rank.hidden and page.active == rank.id) %}
--><a href="/members/{% if page.sort != page.sorts[0] %}{{ page.sort }}/{% endif %}{{ rank.id }}/" style="color: {{ rank.colour }};"{% if page.active == rank.id %} class="dropDownSelected"{% endif %}>{{ rank.name }}{% if rank.multi %}s{% endif %}</a><!--
<a href="{% if page.sort %}{{ urls.format('MEMBERLIST_SORT_RANK', [page.sort, rank.id]) }}{% else %}{{ urls.format('MEMBERLIST_RANK', [rank.id]) }}{% endif %}" style="color: {{ rank.colour }};"{% if page.active == rank.id %} class="dropDownSelected"{% endif %}>{{ rank.name }}{% if rank.multi %}s{% endif %}</a>
{% endif %}
{% endfor %}
--></div>
<div class="dropDownInner" style="float: left;"><!--
--><a class="dropDownDesc">View:</a><!--
</div>
<div class="dropDownInner" style="float: left;">
<a class="dropDownDesc">View:</a>
{% for sort in page.sorts %}
--><a href="/members/{{ sort }}/{% if page.active %}{{ page.active }}/{% endif %}{% if page.page %}p{{ page.page + 1 }}/{% endif %}"{% if page.sort == sort %} class="dropDownSelected"{% endif %}>{{ sort|capitalize }}</a><!--
<a href="{% if page.active and page.page %}{{ urls.format('MEMBERLIST_ALL', [sort, page.active, (page.page + 1)]) }}{% elseif page.active %}{{ urls.format('MEMBERLIST_SORT_RANK', [sort, page.active]) }}{% elseif page.page %}{{ urls.format('MEMBERLIST_SORT_PAGE', [sort, (page.page + 1)]) }}{% else %}{{ urls.format('MEMBERLIST_SORT', [sort]) }}{% endif %}"{% if page.sort == sort %} class="dropDownSelected"{% endif %}>{{ sort|capitalize }}</a>
{% endfor %}
--></div>
</div>
</div>
{% if page.notfound %}
<h1 class="stylised" style="margin-top: 20px;">The requested rank was not found!</h1>
@ -52,10 +54,10 @@
<tbody>
<tr>
<td>
#{{ count }}
#{{ page.active ? count + 1 : count }}
</td>
<td>
<a href="/u/{{ user.id }}" class="default" style="font-weight: bold; color: {{ page.ranks[user.rank_main].colour }};">{{ user.username }}</a>
<a href="{{ urls.format('USER_PROFILE', [user.id]) }}" class="default" style="font-weight: bold; color: {{ page.ranks[user.rank_main].colour }};">{{ user.username }}</a>
</td>
<td>
{{ user.regdate|date(sakura.dateFormat) }}
@ -67,7 +69,7 @@
{% if not user.usertitle %}<i>{{ page.ranks[user.rank_main].title }}</i>{% else %}{{ user.usertitle }}{% endif %}
</td>
<td>
<img src="{{ sakura.contentPath }}/images/flags/{% if user.country|lower == 'eu' %}europeanunion{% else %}{{ user.country|lower }}{% endif %}.png" alt="{% if user.country|lower == 'eu' %}?{% else %}{{ user.country }}{% endif %}" />
<img src="{{ sakura.contentPath }}/images/flags/{{ user.country|lower }}.png" alt="{% if user.country|lower == 'eu' %}?{% else %}{{ user.country }}{% endif %}" />
</td>
</tr>
</tbody>
@ -75,9 +77,9 @@
</table>
{% else %}
{% for user in page.users[page.page] %}
<a href="/u/{{ user.id }}">{# These comment tags are here to prevent the link extending too far
<a href="{{ urls.format('USER_PROFILE', [user.id]) }}">{# These comment tags are here to prevent the link extending too far
#}<div class="userBox" id="u{{ user.id }}">{#
#}<img src="{{ sakura.contentPath }}/pixel.png" alt="{{ user.username }}" style="background: url('/a/{{ user.id }}') no-repeat center / contain;" />{#
#}<img src="{{ sakura.contentPath }}/pixel.png" alt="{{ user.username }}" style="background: url('{{ urls.format('IMAGE_AVATAR', [user.id]) }}') no-repeat center / contain;" />{#
#}<span class="userBoxUserName"{% if page.sort == page.sorts[1] %} style="color: {{ page.ranks[user.rank_main].colour }};"{% endif %}>{#
#}{{ user.username }}{#
#}</span>{#
@ -90,13 +92,13 @@
{% if page.users|length > 1 %}
<div class="pagination">
{% if page.page > 0 %}
<a href="/members/{% if page.sort != page.sorts[0] %}{{ page.sort }}/{% endif %}{% if page.active %}{{ page.active }}/{% endif %}p{{ page.page }}"><span class="fa fa-step-backward"></span></a>
<a href="{% if page.sort and page.active %}{{ urls.format('MEMBERLIST_ALL', [page.sort, page.active, page.page]) }}{% elseif page.sort %}{{ urls.format('MEMBERLIST_SORT_PAGE', [page.sort, page.page]) }}{% elseif page.active %}{{ urls.format('MEMBERLIST_RANK_PAGE', [page.active, page.page]) }}{% else %}{{ urls.format('MEMBERLIST_PAGE', [page.page]) }}{% endif %}"><span class="fa fa-step-backward"></span></a>
{% endif %}
{% for count,navpage in page.users %}
<a href="/members/{% if page.sort != page.sorts[0] %}{{ page.sort }}/{% endif %}{% if page.active %}{{ page.active }}/{% endif %}p{{ count + 1 }}"{% if count == page.page %} class="current"{% endif %}>{{ count + 1 }}</a>
<a href="{% if page.sort and page.active %}{{ urls.format('MEMBERLIST_ALL', [page.sort, page.active, (count + 1)]) }}{% elseif page.sort %}{{ urls.format('MEMBERLIST_SORT_PAGE', [page.sort, (count + 1)]) }}{% elseif page.active %}{{ urls.format('MEMBERLIST_RANK_PAGE', [page.active, (count + 1)]) }}{% else %}{{ urls.format('MEMBERLIST_PAGE', [(count + 1)]) }}{% endif %}"{% if count == page.page %} class="current"{% endif %}>{{ count + 1 }}</a>
{% endfor %}
{% if page.page + 1 < page.users|length %}
<a href="/members/{% if page.sort != page.sorts[0] %}{{ page.sort }}/{% endif %}{% if page.active %}{{ page.active }}/{% endif %}p{{ page.page + 2 }}"><span class="fa fa-step-forward"></span></a>
<a href="{% if page.sort and page.active %}{{ urls.format('MEMBERLIST_ALL', [page.sort, page.active, (page.page + 2)]) }}{% elseif page.sort %}{{ urls.format('MEMBERLIST_SORT_PAGE', [page.sort, (page.page + 2)]) }}{% elseif page.active %}{{ urls.format('MEMBERLIST_RANK_PAGE', [page.active, (page.page + 2)]) }}{% else %}{{ urls.format('MEMBERLIST_PAGE', [(page.page + 2)]) }}{% endif %}"><span class="fa fa-step-forward"></span></a>
{% endif %}
</div>
{% endif %}
@ -104,4 +106,4 @@
{% else %}
{% include 'elements/restricted.tpl' %}
{% endif %}
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,7 +1,9 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content">
<div class="content-column news">
<div class="head">{% if page.view_post %}{{ newsPosts[0].title }}{% elseif newsPosts|length < 1 %}Post does not exist!{% else %}News <a href="/news.xml" class="fa fa-rss news-rss default"></a>{% endif %}</div>
<div class="head">{% if page.view_post %}{{ newsPosts[0].title }}{% elseif newsPosts|length < 1 %}Post does not exist!{% else %}News <a href="{{ urls.format('SITE_NEWS_RSS') }}" class="fa fa-rss news-rss default"></a>{% endif %}</div>
{% if newsPosts|length >= 1 %}
{% if page.view_post %}
{% for newsPost in newsPosts %}
@ -16,13 +18,13 @@
<div>
<div class="pagination" style="float: right;">
{% if page.currentPage > 0 %}
<a href="/news/p{{ page.currentPage }}"><span class="fa fa-step-backward"></span></a>
<a href="{{ urls.format('SITE_NEWS_PAGE', [page.currentPage]) }}"><span class="fa fa-step-backward"></span></a>
{% endif %}
{% for id,npage in newsPosts %}
<a href="/news/p{{ id + 1 }}"{% if id == page.currentPage %} class="current"{% endif %}>{{ id + 1 }}</a>
<a href="{{ urls.format('SITE_NEWS_PAGE', [(id + 1)]) }}"{% if id == page.currentPage %} class="current"{% endif %}>{{ id + 1 }}</a>
{% endfor %}
{% if page.currentPage + 1 < newsPosts|length %}
<a href="/news/p{{ page.currentPage + 2 }}"><span class="fa fa-step-forward"></span></a>
<a href="{{ urls.format('SITE_NEWS_PAGE', [(page.currentPage + 2)]) }}"><span class="fa fa-step-forward"></span></a>
{% endif %}
</div>
<div class="clear"></div>
@ -40,4 +42,4 @@
{% endif %}
</div>
</div>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,7 +1,9 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content standalone" style="text-align: center;">
<h1 class="stylised" style="margin: 1em auto;">Thank you for your contribution!</h1>
<h1 class="fa fa-heart stylised" style="font-size: 20em;"></h1>
<h3>Your Tenshi will expire on {{ page.expiration|date(sakura.dateFormat) }}.</h3>
</div>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -0,0 +1 @@
{% extends 'global/master.tpl' %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content" style="background: #FFF;">
<div class="content-column news">
<div class="head">Search</div>
@ -17,4 +19,4 @@
<gcse:searchresults></gcse:searchresults>
</div>
</div>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content settings messages">
<div class="content-right content-column">
{% include 'elements/settingsNav.tpl' %}
@ -16,4 +18,4 @@
</div>
<div class="clear"></div>
</div>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,15 +1,17 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
{% if page.fail %}
<div class="headerNotify">
<h1>The payment failed or was cancelled!</h1>
<p>Something went wrong while processing the transaction, your PayPal account wasn't charged.</p>
</div>
<div class="headerNotify">
<h1>The payment failed or was cancelled!</h1>
<p>Something went wrong while processing the transaction, your PayPal account wasn't charged.</p>
</div>
{% endif %}
<div class="content support">
<div class="head">Support {{ sakura.siteName }}</div>
<div style="font-size: .9em; margin-bottom: 10px;">
<p>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!</p>
<h3><a href="/support/tracker" class="default">Ever wonder what happens on the financial side of things? View the donation tracker!</a></h3>
<h3><a href="{{ urls.format('SITE_DONATE_TRACK') }}" class="default">Ever wonder what happens on the financial side of things? View the donation tracker!</a></h3>
</div>
{% if page.current[0] %}
<div class="sectionHeader">
@ -105,7 +107,7 @@
{% endif %}
</div>
{% if session.checkLogin and user.checkPermission('SITE', 'OBTAIN_PREMIUM') %}
<form action="/support" method="post" id="purchaseForm" class="hidden">
<form action="{{ urls.format('SITE_PREMIUM') }}" method="post" id="purchaseForm" class="hidden">
<input type="hidden" name="mode" value="purchase" />
<input type="hidden" name="time" value="{{ php.time }}" />
<input type="hidden" name="session" value="{{ php.sessionid }}" />
@ -115,4 +117,4 @@
window.onload = function() { document.getElementById('totalAmount').innerHTML = ({{ page.price }}).formatMoney(2); };
</script>
{% endif %}
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,4 +1,6 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
<div class="content support">
<div class="head">Donation Tracker</div>
<h1 class="stylised" style="margin: 1em auto; text-align: center;">Our current overall balance is &#8364;{{ page.premiumData.balance|number_format(2) }}</h1>
@ -36,7 +38,7 @@
{% for supporter in page.premiumTable[page.currentPage] %}
<tr>
<td>
<a href="/u/{{ page.premiumData.users[supporter.uid].data.id }}" class="default" style="color: {{ page.premiumData.users[supporter.uid].colour }}; text-shadow: 0 0 7px {% if page.premiumData.users[supporter.uid].colour != 'inherit' %}{{ page.premiumData.users[supporter.uid].colour }}{% else %}#222{% endif %};">{{ page.premiumData.users[supporter.uid].data.username }}</a>
<a href="{{ urls.format('USER_PROFILE', [page.premiumData.users[supporter.uid].data.id]) }}" class="default" style="color: {{ page.premiumData.users[supporter.uid].colour }}; text-shadow: 0 0 7px {% if page.premiumData.users[supporter.uid].colour != 'inherit' %}{{ page.premiumData.users[supporter.uid].colour }}{% else %}#222{% endif %};">{{ page.premiumData.users[supporter.uid].data.username }}</a>
</td>
<td style="color: {% if supporter.amount > 0 %}#0A0{% else %}#A00{% endif %};">
&#8364;{{ supporter.amount|number_format(2) }}
@ -51,16 +53,16 @@
{% if page.premiumTable|length > 1 %}
<div class="pagination" style="float: right;">
{% if page.currentPage > 0 %}
<a href="/support/tracker/{{ page.currentPage }}"><span class="fa fa-step-backward"></span></a>
<a href="{{ urls.format('SITE_DONATE_TRACK_PAGE', [page.currentPage]) }}"><span class="fa fa-step-backward"></span></a>
{% endif %}
{% for count,navpage in page.premiumTable %}
<a href="/support/tracker/{{ count + 1 }}"{% if count == page.currentPage %} class="current"{% endif %}>{{ count + 1 }}</a>
<a href="{{ urls.format('SITE_DONATE_TRACK_PAGE', [(count + 1)]) }}"{% if count == page.currentPage %} class="current"{% endif %}>{{ count + 1 }}</a>
{% endfor %}
{% if page.currentPage + 1 < page.premiumTable|length %}
<a href="/support/tracker/{{ page.currentPage + 2 }}"><span class="fa fa-step-forward"></span></a>
<a href="{{ urls.format('SITE_DONATE_TRACK_PAGE', [(page.currentPage + 2)]) }}"><span class="fa fa-step-forward"></span></a>
{% endif %}
</div>
<div class="clear"></div>
{% endif %}
</div>
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -1,11 +1,13 @@
{% include 'global/header.tpl' %}
{% extends 'global/master.tpl' %}
{% block content %}
{% if profile.checkPermission('SITE', 'DEACTIVATED') or profile.data.password_algo == 'nologin' or (profile.checkPermission('SITE', 'RESTRICTED') and (user.data.id != profile.data.id and not user.checkPermission('MANAGE', 'USE_MANAGE'))) %}
<div class="content standalone" style="padding: 20px;">
<h1>The requested user does not exist!</h1>
There are a few possible reasons for this:
<ul style="padding-left: 40px;">
<li>They changed their username.</li>
<li>They may have been <a href="/faq#abyss" class="default">abyss'd</a>.</li>
<li>They may have been <a href="{{ urls.format('SITE_FAQ') }}#abyss" class="default">abyss'd</a>.</li>
<li>You made a typo.</li>
<li>They never existed.</li>
</ul>
@ -14,19 +16,19 @@
<div class="content profile">
<div class="{% if profile.userPage|length > 1 %}content-right {% endif %}content-column">
<div style="text-align: center;">
<img src="/a/{{ profile.data.id }}" alt="{{ profile.data.username }}'s Avatar" class="default-avatar-setting" style="box-shadow: 0 3px 7px #{% if profile.checkOnline %}484{% else %}844{% endif %};" /><br />
<img src="{{ urls.format('IMAGE_AVATAR', [profile.data.id]) }}" alt="{{ profile.data.username }}'s Avatar" class="default-avatar-setting" style="box-shadow: 0 3px 7px #{% if profile.checkOnline %}484{% else %}844{% endif %};" /><br />
{% if profile.data.rank_main > 1 and profile.checkBan|length < 1 %}
<span style="font-size: .8em;">{{ profile.userTitle }}</span>
<h1 style="color: {{ profile.colour }}; text-shadow: 0 0 7px {% if profile.colour != 'inherit' %}{{ profile.colour }}{% else %}#222{% endif %}; padding: 0 0 2px;">{{ profile.data.username }}</h1>
{% if profile.checkPremium[0] %}<img src="{{ sakura.contentPath }}/images/tenshi.png" alt="Tenshi" /> {% endif %}<img src="{{ sakura.contentPath }}/images/flags/{% if profile.country.short|lower == 'eu' %}europeanunion{% else %}{{ profile.country.short|lower }}{% endif %}.png" alt="{{ profile.country.short }}" /> <span style="font-size: .9em; line-height: 11px;">{{ profile.country.long }}</span>
{% if profile.checkPremium[0] %}<img src="{{ sakura.contentPath }}/images/tenshi.png" alt="Tenshi" /> {% endif %}<img src="{{ sakura.contentPath }}/images/flags/{{ profile.country.short|lower }}.png" alt="{{ profile.country.short }}" /> <span style="font-size: .9em; line-height: 11px;">{{ profile.country.long }}</span>
{% if session.checkLogin %}
<div class="user-actions">
{% if user.data.id == profile.data.id %}
<a class="fa fa-pencil-square-o" title="Edit your profile" href="/settings/profile"></a>
<a class="fa fa-pencil-square-o" title="Edit your profile" href="{{ urls.format('SETTING_MODE', ['general', 'profile']) }}"></a>
{% else %}
{% if profile.checkFriends(user.data.id) != 0 %}<a class="fa fa-{% if profile.checkFriends(user.data.id) == 2 %}heart{% else %}star{% endif %}" title="You are friends"></a>{% endif %}
<a class="fa fa-user-{% if profile.checkFriends(user.data.id) == 0 %}plus{% else %}times{% endif %}" title="{% if profile.checkFriends(user.data.id) == 0 %}Add {{ legacyprofile.data.username }} as a friend{% else %}Remove friend{% endif %}" href="/friends?{% if profile.checkFriends(user.data.id) == 0 %}add{% else %}remove{% endif %}={{ profile.data.id }}&amp;session={{ php.sessionid }}&amp;time={{ php.time }}&amp;redirect={{ sakura.currentPage }}" id="profileFriendToggle"></a>
<a class="fa fa-flag" title="Report {{ profile.data.username }}" href="/u/{{ profile.data.id }}/report"></a>
<a class="fa fa-user-{% if profile.checkFriends(user.data.id) == 0 %}plus{% else %}times{% endif %}" title="{% if profile.checkFriends(user.data.id) == 0 %}Add {{ legacyprofile.data.username }} as a friend{% else %}Remove friend{% endif %}" href="{% if profile.checkFriends(user.data.id) == 0 %}{{ urls.format('FRIEND_ADD', [profile.data.id, php.sessionid, php.time, sakura.currentPage]) }}{% else %}{{ urls.format('FRIEND_REMOVE', [profile.data.id, php.sessionid, php.time, sakura.currentPage]) }}{% endif %}" id="profileFriendToggle"></a>
<a class="fa fa-flag" title="Report {{ profile.data.username }}" href="{{ urls.format('USER_REPORT', [profile.data.id]) }}"></a>
{% endif %}
</div>
{% endif %}
@ -96,4 +98,4 @@
<div class="clear"></div>
</div>
{% endif %}
{% include 'global/footer.tpl' %}
{% endblock %}

View file

@ -14,8 +14,6 @@ RewriteBase /
Options +FollowSymLinks -Indexes
# Rewrite Rules
RewriteRule ^feedback/?$ https://github.com/circlestorm/Sakura/issues [L,QSA]
RewriteRule ^credits/?$ credits.php [L,QSA]
RewriteRule ^index/?$ index.php [L,QSA]
RewriteRule ^login/?$|^logout/?$|^activate/?$|^register/?$|^forgotpassword/?|^authenticate/?$ authenticate.php [L,QSA]
RewriteRule ^support/?$ support.php [L,QSA]
@ -82,5 +80,5 @@ RewriteRule ^forum/post/([0-9]+)/(quote|reply)/?$ posting.php?p=$1&quote=$1 [L,Q
# Management
RewriteRule ^manage/?$ manage.php [L,QSA]
RewriteRule ^manage/([a-z\-]+)/?$ manage.php?page=$1&sub=0 [L,QSA]
RewriteRule ^manage/([a-z\-]+)/([a-z\-]+)/?$ manage.php?page=$1&sub=$2 [L,QSA]
RewriteRule ^manage/([a-z\-]+)/?$ manage.php?cat=$1&mode=0 [L,QSA]
RewriteRule ^manage/([a-z\-]+)/([a-z\-]+)/?$ manage.php?cat=$1&mode=$2 [L,QSA]

View file

@ -13,4 +13,4 @@ require_once str_replace(basename(__DIR__), '', dirname(__FILE__)) .'_sakura/sak
header('HTTP/1.0 404 Not Found');
// Print page contents
print Templates::render('errors/http404.tpl', $renderData);
print Templates::render('global/notfound.tpl', $renderData);

View file

@ -23,7 +23,7 @@ if(isset($_REQUEST['mode'])) {
$renderData['page'] = [
'title' => 'Action failed',
'redirect' => '/authenticate',
'redirect' => $urls->format('AUTH_ACTION'),
'message' => 'Timestamps differ too much, refresh the page and try again.',
'success' => 0
];
@ -38,7 +38,7 @@ if(isset($_REQUEST['mode'])) {
$renderData['page'] = [
'title' => 'Action failed',
'redirect' => '/authenticate',
'redirect' => $urls->format('AUTH_ACTION'),
'message' => 'Invalid session, please try again.',
'success' => 0
];
@ -59,7 +59,7 @@ if(isset($_REQUEST['mode'])) {
// Add page specific things
$renderData['page'] = [
'title' => 'Authentication',
'redirect' => '/',
'redirect' => $urls->format('SITE_HOME'),
'message' => 'You are already authenticated. Redirecting...',
'success' => 1
];
@ -79,7 +79,7 @@ if(isset($_REQUEST['mode'])) {
// Add page specific data
$renderData['page'] = [
'title' => 'Logout',
'redirect' => ($logout ? $_REQUEST['redirect'] : '/authenticate'),
'redirect' => ($logout ? $_REQUEST['redirect'] : $urls->format('SITE_LOGIN')),
'message' => $logout ? 'You are now logged out.' : 'An unknown error occurred.',
'success' => $logout ? 1 : 0
];
@ -105,7 +105,7 @@ if(isset($_REQUEST['mode'])) {
// Add page specific things
$renderData['page'] = [
'title' => 'Forgot Password',
'redirect' => ($passforget[0] ? '/' : $_SERVER['PHP_SELF'] .'?pw=true&uid='. $_REQUEST['uid'] .'&verk='. $_REQUEST['verk']),
'redirect' => ($passforget[0] ? $urls->format('SITE_LOGIN') : $_SERVER['PHP_SELF'] .'?pw=true&uid='. $_REQUEST['uid'] .'&verk='. $_REQUEST['verk']),
'message' => $messages[$passforget[1]],
'success' => $passforget[0]
];
@ -130,7 +130,7 @@ if(isset($_REQUEST['mode'])) {
// Add page specific things
$renderData['page'] = [
'title' => 'Activate account',
'redirect' => '/authenticate',
'redirect' => $urls->format('SITE_LOGIN'),
'message' => $messages[$activate[1]],
'success' => $activate[0]
];
@ -154,7 +154,7 @@ if(isset($_REQUEST['mode'])) {
// Add page specific things
$renderData['page'] = [
'title' => 'Resend Activation',
'redirect' => '/authenticate',
'redirect' => $urls->format('SITE_HOME'),
'message' => $messages[$resend[1]],
'success' => $resend[0]
];
@ -180,7 +180,7 @@ if(isset($_REQUEST['mode'])) {
// Add page specific things
$renderData['page'] = [
'title' => 'Login',
'redirect' => $login[0] ? $_REQUEST['redirect'] : '/authenticate',
'redirect' => $login[0] ? $_REQUEST['redirect'] : $urls->format('SITE_LOGIN'),
'message' => $messages[$login[1]],
'success' => $login[0]
];
@ -230,7 +230,7 @@ if(isset($_REQUEST['mode'])) {
// Add page specific things
$renderData['page'] = [
'title' => 'Register',
'redirect' => ($register[0] ? '/' : '/authenticate'),
'redirect' => ($register[0] ? $urls->format('SITE_LOGIN') : $urls->format('SITE_REGISTER')),
'message' => $messages[$register[1]],
'success' => $register[0]
];
@ -254,7 +254,7 @@ if(isset($_REQUEST['mode'])) {
// Add page specific things
$renderData['page'] = [
'title' => 'Lost Password',
'redirect' => '/authenticate',
'redirect' => $urls->format('SITE_FORGOT_PASSWORD'),
'message' => $messages[$passforgot[1]],
'success' => $passforgot[0]
];
@ -276,7 +276,7 @@ if(isset($_REQUEST['mode'])) {
. '|'
. $renderData['page']['redirect']
) :
Templates::render('errors/information.tpl', $renderData);
Templates::render('global/information.tpl', $renderData);
exit;
}
@ -287,11 +287,11 @@ $renderData['page'] = [
];
$renderData['auth'] = [
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/',
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $urls->format('SITE_HOME'),
'blockRegister' => [
'do' => false
]
];
@ -302,11 +302,11 @@ if(Users::checkLogin()) {
// Add page specific things
$renderData['page'] = [
'title' => 'Authentication',
'redirect' => '/',
'redirect' => $urls->format('SITE_HOME'),
'message' => 'You are already logged in, log out to access this page.'
];
print Templates::render('errors/information.tpl', $renderData);
print Templates::render('global/information.tpl', $renderData);
exit;
}

View file

@ -343,9 +343,10 @@ a#gotop.exit {
.standalone {
background: #C2AEEE;
padding: 10px;
width: auto;
max-width: 1024px;
}
.standalone > div {
padding: 5px 10px;
}
.private-message {
@ -671,13 +672,14 @@ a#gotop.exit {
.headerNotify {
margin: 10px auto;
padding: 2px 3px;
padding: 10px 3px;
width: auto;
max-width: 1024px;
border: 1px solid #9475B2;
box-shadow: 0 0 3px #9475B2;
border-radius: 3px;
background: #D3BFFF;
background: repeating-linear-gradient(-45deg, #C2AFFE, #C2AFFE 10px, #D3BFFF 10px, #D3BFFF 20px);
display: block;
text-align: center;
}

View file

@ -0,0 +1,2 @@
# shhh
ErrorDocument 404 /content/images/flags/xx.png

View file

@ -8,48 +8,7 @@ namespace Sakura;
// Include components
require_once str_replace(basename(__DIR__), '', dirname(__FILE__)) .'_sakura/sakura.php';
/*
// Get group data
if(isset($_GET['g'])) {
$renderData['profile'] = [
'notset' => false,
'user' => ($_PROFILE_USER_DATA = Users::getUser(($_USER_USERNAME_ID = Users::userExists($_GET['u'], false)) ? $_USER_USERNAME_ID : $_GET['u'])),
'rank' => ($_PROFILE_RANK_DATA = Users::getRank($_PROFILE_USER_DATA['rank_main'])),
'colour' => ($_PROFILE_USER_DATA['name_colour'] == null ? $_PROFILE_RANK_DATA['colour'] : $_PROFILE_USER_DATA['name_colour']),
'ranktitle' => ($_PROFILE_USER_DATA['usertitle'] == null ? $_PROFILE_RANK_DATA['title'] : $_PROFILE_USER_DATA['usertitle']),
'data' => ($_PROFILE_PROFILE_DATA = Users::getUserProfileData($_PROFILE_USER_DATA, true)),
'country' => Main::getCountryName($_PROFILE_USER_DATA['country']),
'istenshi' => Users::checkUserTenshi($_PROFILE_USER_DATA['id']),
'online' => Users::checkUserOnline($_PROFILE_USER_DATA['id']),
'profilePage' => Users::getProfilePage($_PROFILE_PROFILE_DATA, true),
'fields' => Users::getUserProfileFields($_PROFILE_PROFILE_DATA, true),
'warnings' => Users::getWarnings($_PROFILE_USER_DATA['id']),
'friend' => Users::checkFriend($_PROFILE_USER_DATA['id'])
];
$renderData['page'] = [
'title' => ($_PROFILE_USER_DATA['id'] < 1 || $_PROFILE_USER_DATA['password_algo'] == 'nologin' ? 'User not found!' : 'Profile of '. $_PROFILE_USER_DATA['username']),
'style' => (!empty($_PROFILE_PROFILE_DATA['profileBackground']) ? [
'#userBackground' => [
'background' => 'url("/bg/'. $_PROFILE_USER_DATA['id'] .'") no-repeat center center / cover transparent !important',
'position' => 'fixed',
'top' => '0',
'bottom' => '0',
'right' => '0',
'left' => '0',
'z-index' => '-1'
]
] : null)
];
} else {
$renderData['profile']['notset'] = true;
$renderData['page']['title'] = 'User not found!';
}
// Print page contents
print Templates::render('main/profile.tpl', $renderData);
*/
print Templates::render('group/index.tpl', $renderData);

View file

@ -62,9 +62,9 @@ $renderData['stats'] = [
'userCount' => ($_INDEX_USER_COUNT = count($_INDEX_USERS = Users::getAllUsers(false))),
'newestUser' => ($_INDEX_NEWEST_USER = new User(Users::getNewestUserId())),
'lastRegDate' => ($_INDEX_LAST_REGDATE = date_diff(date_create(date('Y-m-d', $_INDEX_NEWEST_USER->data['regdate'])), date_create(date('Y-m-d')))->format('%a')) .' day'. ($_INDEX_LAST_REGDATE == 1 ? '' : 's'),
'onlineUsers' => Users::checkAllOnline(),
'topicCount' => ($_TOPICS = count(Database::fetch('topics'))),
'postCount' => ($_POSTS = count(Database::fetch('posts')))
'topicCount' => ($_TOPICS = count(Database::fetch('topics'))),
'postCount' => ($_POSTS = count(Database::fetch('posts'))),
'onlineUsers' => Users::checkAllOnline()
];
// Print page contents

View file

@ -19,7 +19,7 @@ $renderData['page'] = [
'sort' => isset($_GET['sort']) && $_GET['sort'] && in_array($_GET['sort'], $_MEMBERLIST_SORTS) ? $_GET['sort'] : $_MEMBERLIST_SORTS[0],
'title' => isset($_GET['rank']) && $_GET['rank'] && !$_MEMBERLIST_NFOUND ? 'Viewing '. $_MEMBERLIST_RANKS[$_GET['rank']]['name'] . ($_MEMBERLIST_RANKS[$_GET['rank']]['multi'] ? 's' : '') : 'Member List',
'page' => isset($_GET['page']) && ($_GET['page'] - 1) >= 0 ? $_GET['page'] - 1 : 0,
'users' => array_chunk($_MEMBERLIST_ACTIVE && !$_MEMBERLIST_NFOUND ? Users::getUsersInRank($_MEMBERLIST_ACTIVE, null, true, true) : Users::getAllUsers(), 30, true)
'users' => array_chunk($_MEMBERLIST_ACTIVE && !$_MEMBERLIST_NFOUND ? Users::getUsersInRank($_MEMBERLIST_ACTIVE, null, true, true) : Users::getAllUsers(), Configuration::getConfig('members_per_page'), true)
];

View file

@ -9,4 +9,4 @@ namespace Sakura;
// Include components
require_once str_replace(basename(__DIR__), '', dirname(__FILE__)) .'_sakura/sakura.php';
print 'not yet';
print Templates::render('main/report.tpl', $renderData);

View file

@ -62,14 +62,14 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$continue = true;
// Referrer
$redirect = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/');
$redirect = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $urls->format('SITE_INDEX'));
// Compare time and session so we know the link isn't forged
if(!isset($_REQUEST['add']) && !isset($_REQUEST['remove'])) {
if(!isset($_REQUEST['ajax'])) {
header('Location: /settings/friends');
header('Location: '. $redirect);
exit;
}
@ -207,13 +207,16 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
. '|'
. $renderData['page']['redirect']
) :
Templates::render('errors/information.tpl', $renderData);
Templates::render('global/information.tpl', $renderData);
exit;
} elseif(isset($_POST['submit']) && isset($_POST['submit'])) {
$continue = true;
// Set redirector
$redirect = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $urls->format('SETTINGS_INDEX');
// Check if the user is logged in
if(!Users::checkLogin() || !$continue) {
@ -236,7 +239,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => 'Session expired',
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'Your session has expired, please refresh the page and try again.',
'success' => 0
@ -283,7 +286,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => $msgTitle,
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'You are not allowed to alter your '. strtolower($msgTitle) .'.',
'success' => 0
@ -305,7 +308,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => $msgTitle,
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'No file was uploaded.',
'success' => 0
@ -346,7 +349,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => $msgTitle,
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => $msg,
'success' => 0
@ -369,7 +372,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => $msgTitle,
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'Uploaded file is not an image.',
'success' => 0
@ -386,7 +389,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => $msgTitle,
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'This filetype is not allowed.',
'success' => 0
@ -403,7 +406,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => $msgTitle,
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'The resolution of this picture is too big.',
'success' => 0
@ -420,7 +423,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => $msgTitle,
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'The resolution of this picture is too small.',
'success' => 0
@ -437,7 +440,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => $msgTitle,
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'The filesize of this file is too large.',
'success' => 0
@ -467,7 +470,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => $msgTitle,
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'Something went wrong, please try again.',
'success' => 0
@ -492,7 +495,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => $msgTitle,
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'Updated your '. strtolower($msgTitle) .'!',
'success' => 1
@ -549,7 +552,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => 'Profile update',
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'Your profile has been updated!',
'success' => 1
@ -586,7 +589,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => 'Options change',
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'Changed your options!',
'success' => 1
@ -595,7 +598,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
break;
// Userpage
case 'userpage':
/*case 'userpage':
// Base64 encode the userpage
$userPage = base64_encode($_POST['userpage']);
@ -607,13 +610,13 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => 'Userpage',
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'Your userpage has been updated!',
'success' => 1
];
break;
break;*/
// Fallback
default:
@ -622,7 +625,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
$renderData['page'] = [
'title' => 'Unknown action',
'redirect' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '/settings',
'redirect' => $redirect,
'message' => 'The requested method does not exist.',
'success' => 0
@ -645,7 +648,7 @@ if(isset($_REQUEST['request-notifications']) && $_REQUEST['request-notifications
. '|'
. $renderData['page']['redirect']
) :
Templates::render('errors/information.tpl', $renderData);
Templates::render('global/information.tpl', $renderData);
exit;
}
@ -981,7 +984,7 @@ if(Users::checkLogin()) {
if(!$category || empty($category) || !$mode || empty($mode) || !$pages[$category]['modes'][$mode]['access']) {
header('HTTP/1.0 404 Not Found');
print Templates::render('errors/http404.tpl', $renderData);
print Templates::render('global/notfound.tpl', $renderData);
exit;
}

View file

@ -15,7 +15,7 @@ if(isset($_REQUEST['mode']) && Users::checkLogin() && Permissions::check('SITE',
// Initialise Payments class
if(!Payments::init()) {
header('Location: /support?fail=true');
header('Location: '. $urls->format('SITE_PREMIUM') .'?fail=true');
} else {
@ -27,7 +27,7 @@ if(isset($_REQUEST['mode']) && Users::checkLogin() && Permissions::check('SITE',
// Compare time and session so we know the link isn't forged
if(!isset($_REQUEST['time']) || $_REQUEST['time'] < time() - 1000) {
header('Location: /support?fail=true');
header('Location: '. $urls->format('SITE_PREMIUM') .'?fail=true');
break;
}
@ -35,7 +35,7 @@ if(isset($_REQUEST['mode']) && Users::checkLogin() && Permissions::check('SITE',
// Match session ids for the same reason
if(!isset($_REQUEST['session']) || $_REQUEST['session'] != session_id()) {
header('Location: /support?fail=true');
header('Location: '. $urls->format('SITE_PREMIUM') .'?fail=true');
break;
}
@ -43,7 +43,7 @@ if(isset($_REQUEST['mode']) && Users::checkLogin() && Permissions::check('SITE',
// Half if shit isn't gucci
if(!isset($_POST['months']) || !is_numeric($_POST['months']) || (int)$_POST['months'] < 1 || (int)$_POST['months'] > Configuration::getConfig('premium_amount_max')) {
header('Location: /support?fail=true');
header('Location: '. $urls->format('SITE_PREMIUM') .'?fail=true');
} else {
@ -55,7 +55,7 @@ if(isset($_REQUEST['mode']) && Users::checkLogin() && Permissions::check('SITE',
$itemName = Configuration::getConfig('sitename') .' Premium - '. (string)$_POST['months'] .' month'. ((int)$_POST['months'] == 1 ? '' : 's');
// Attempt to create a transaction
if($transaction = Payments::createTransaction($total, $itemName, Configuration::getConfig('sitename') .' Premium Purchase', 'http://'. Configuration::getConfig('url_main') .'/support')) {
if($transaction = Payments::createTransaction($total, $itemName, Configuration::getConfig('sitename') .' Premium Purchase', 'http://'. Configuration::getConfig('url_main') . $urls->format('SITE_PREMIUM'))) {
// Store the amount of months in the global session array
$_SESSION['premiumMonths'] = (int)$_POST['months'];
@ -65,7 +65,7 @@ if(isset($_REQUEST['mode']) && Users::checkLogin() && Permissions::check('SITE',
} else {
header('Location: /support?fail=true');
header('Location: '. $urls->format('SITE_PREMIUM') .'?fail=true');
}
@ -93,18 +93,18 @@ if(isset($_REQUEST['mode']) && Users::checkLogin() && Permissions::check('SITE',
Main::updatePremiumTracker(Session::$userId, ((float)Configuration::getConfig('premium_price_per_month') * $_SESSION['premiumMonths']), $currentUser->data['username'] .' bought premium for '. $_SESSION['premiumMonths'] .' month'. ($_SESSION['premiumMonths'] == 1 ? '' : 's') .'.');
// Redirect to the complete
header('Location: ?mode=complete');
header('Location: '. $urls->format('SITE_PREMIUM') .'?mode=complete');
exit;
}
}
header('Location: /support?fail=true');
header('Location: '. $urls->format('SITE_PREMIUM') .'?fail=true');
break;
case 'complete':
print Templates::render('errors/premiumComplete.tpl', array_merge([
print Templates::render('main/premiumcomplete.tpl', array_merge([
'page' => [
'title' => 'Premium purchase complete!',
'expiration' => ($prem = Users::checkUserPremium(Session::$userId)[2]) !== null ? $prem : 0
@ -113,7 +113,7 @@ if(isset($_REQUEST['mode']) && Users::checkLogin() && Permissions::check('SITE',
break;
default:
header('Location: /support');
header('Location: '. $urls->format('SITE_PREMIUM'));
break;
}

View file

@ -24,7 +24,7 @@ if(!$forum) {
];
// Print template
print Templates::render('errors/information.tpl', $renderData);
print Templates::render('global/information.tpl', $renderData);
exit;
}
@ -42,7 +42,7 @@ if($forum['forum']['forum_type'] === 2) {
];
// Print template
print Templates::render('errors/information.tpl', $renderData);
print Templates::render('global/information.tpl', $renderData);
exit;
}

View file

@ -24,7 +24,7 @@ if(!$topic) {
];
// Print template
print Templates::render('errors/information.tpl', $renderData);
print Templates::render('global/information.tpl', $renderData);
exit;
}