Add sitter permission

Add sitter permission
This commit is contained in:
novgorodschi catalin
2026-08-11 12:20:59 +03:00
parent adb29798e1
commit e7c9c61ef8
21 changed files with 616 additions and 32 deletions
+25 -2
View File
@@ -360,19 +360,42 @@ class Account {
// Vacation mode by Shadow
$database->removevacationmode($userData['id']);
/**
* Marcam sesiunea ca fiind de SITTER si retinem CARE sitter e.
*
* Pana acum, dupa autentificare sesiunea unui sitter era identica cu a
* proprietarului - nu exista nimic in $_SESSION care sa spuna ca cel din
* spatele tastaturii e altcineva. Flagul "sit" din tabela online nu ajuta:
* e per cont (nu per sesiune), se scrie cu INSERT IGNORE (deci nu se
* actualizeaza daca randul exista deja) si nu spune care dintre cei doi
* sitteri s-a conectat.
*
* $_SESSION['sitter_uid'] e sursa de adevar pentru permisiuni.
*/
$sitterUid = 0;
if ($database->login($username, $password)) {
$database->UpdateOnline("login", $username, time(), $userData['id']);
} elseif ($database->sitterLogin($username, $password)) {
$database->UpdateOnline("sitter", $username, time(), $userData['id']);
} else {
$sitterUid = (int) $database->sitterLogin($username, $password);
if ($sitterUid > 0) {
$database->UpdateOnline("sitter", $username, time(), $userData['id']);
}
}
setcookie("COOKUSR", $username, time() + COOKIE_EXPIRE, COOKIE_PATH);
$session->login($username);
// dupa Login(), ca sa nu fie suprascris de initializarea sesiunii
$_SESSION['sitter_uid'] = $sitterUid;
}
private function Logout() {
global $session, $database;
unset($_SESSION['wid']);
// altfel un login normal facut imediat dupa ar mosteni flagul de sitter
unset($_SESSION['sitter_uid']);
// actualizează statusul "activ" al utilizatorului
$database->activeModify($database->escape($session->username), 1);
// actualizează ultima activitate online
+11 -2
View File
@@ -556,8 +556,17 @@ class AllianceBonus
if ($triple) {
$cost = defined('ALLIANCE_BONUS_TRIPLE_GOLD') ? (int) ALLIANCE_BONUS_TRIPLE_GOLD : 3;
$database->modifyGold($uid, $cost, 0);
$session->gold -= $cost;
// PERMISIUNI SITTER: donatia tripla costa aur. Daca sitterul nu are
// dreptul, donatia simpla (deja inregistrata mai sus) ramane valida,
// doar bonusul platit nu se aplica.
if (!isset($session) || !method_exists($session, 'sitterCan')
|| $session->sitterCan(SITTER_PERM_GOLD)) {
if ($database->spendGold($uid, $cost, 'Alliance bonus triple donation')) {
$session->gold -= $cost;
}
}
}
mysqli_query($this->db, "COMMIT");
+19 -2
View File
@@ -1604,9 +1604,26 @@ class Building {
}
$spent = ($countMasterGold && $countPlus2Gold) ? 3 : 2;
$newgold = $this->sess->gold - $spent;
$this->db->updateUserField($this->sess->uid, 'gold', $newgold, 1);
/**
* PERMISIUNI SITTER: "cheltuie aur".
* Verificam inainte de scadere; daca nu are voie, nu se ia nimic.
*/
if (isset($this->sess) && method_exists($this->sess, 'sitterCan')
&& !$this->sess->sitterCan(SITTER_PERM_GOLD)) {
return;
}
/**
* spendGold() in loc de scriere absoluta: scaderea e relativa si atomica,
* deci dispare riscul de dubla cheltuire descris in comentariul de mai jos
* (soldul din sesiune putea fi vechi de pana la 30 de secunde).
*/
if (!$this->db->spendGold($this->sess->uid, $spent, 'Finish all constructions')) {
return;
}
$newgold = $this->sess->gold - $spent;
$this->db->addGoldFinLog(
$this->vil->wid,
+77 -7
View File
@@ -382,9 +382,32 @@ trait DatabaseUserQueries {
return $cachedResult;
}
/** @var array cache per request: username => uid-ul sitterului care s-a potrivit */
private static $sitterLoginCache = array();
/**
* Autentificare ca sitter pe contul $username.
*
* INTOARCE ACUM UID-UL SITTERULUI (0 = esec), nu doar true/false.
* Fara asta nu se putea sti CARE dintre cei doi sitteri s-a conectat,
* deci nu aveai cum sa aplici permisiuni diferite pentru sit1 si sit2.
* Un uid e mereu > 0, iar 0 e falsy, deci apelurile vechi de forma
* "if ($database->sitterLogin(...))" continua sa functioneze identic.
*
* Account.php o cheama de doua ori pe acelasi login (o data la validare,
* o data ca sa scrie in tabela online). Cache-ul de mai jos face ca a
* doua verificare de parola sa nu se mai execute - password_verify e
* intentionat lent, deci conteaza.
*/
function sitterLogin($username, $password) {
list($username, $password) = $this->escape_input($username, $password);
$cacheKey = $username . '|' . md5($password);
if (isset(self::$sitterLoginCache[$cacheKey])) {
return self::$sitterLoginCache[$cacheKey];
}
$q = "SELECT sit1,sit2 FROM " . TB_PREFIX . "users where username = '$username' and access != " . BANNED ." LIMIT 1";
$result = mysqli_query($this->dblink,$q);
$dbarray = mysqli_fetch_array($result);
@@ -395,7 +418,7 @@ trait DatabaseUserQueries {
* null". Iesim din start - oricum nu are cine sa fie sitter.
*/
if (!is_array($dbarray)) {
return false;
return self::$sitterLoginCache[$cacheKey] = 0;
}
$dbarray2 = null;
@@ -412,16 +435,19 @@ trait DatabaseUserQueries {
$dbarray3 = mysqli_fetch_array($result3);
}
if($dbarray['sit1'] != 0 || $dbarray['sit2'] != 0) {
// Verificam separat, ca sa stim CARE sitter s-a potrivit.
// sit1/sit2 pot fi setati independent, deci unul dintre randuri
// poate lipsi; fara ?? '' iesea acelasi warning pe null.
if(password_verify($password, (string) ($dbarray2['password'] ?? ''))
|| password_verify($password, (string) ($dbarray3['password'] ?? ''))) {
return true;
// poate lipsi; fara ?? '' iesea warning pe null.
if (password_verify($password, (string) ($dbarray2['password'] ?? ''))) {
return self::$sitterLoginCache[$cacheKey] = (int) $dbarray['sit1'];
} else if (password_verify($password, (string) ($dbarray3['password'] ?? ''))) {
return self::$sitterLoginCache[$cacheKey] = (int) $dbarray['sit2'];
} else {
return false;
return self::$sitterLoginCache[$cacheKey] = 0;
}
} else {
return false;
// contul nu are niciun sitter definit
return self::$sitterLoginCache[$cacheKey] = 0;
}
}
@@ -446,6 +472,50 @@ trait DatabaseUserQueries {
return isset($dbarray['timestamp']) ? (int)$dbarray['timestamp'] : 0;
}
/**
* PUNCTUL UNIC DE CHELTUIRE A AURULUI.
*
* Scade $amount aur de la $uid, ATOMIC: conditia "gold >= amount" e in
* acelasi UPDATE, deci doua cereri simultane nu pot scoate soldul pe minus.
* Intoarce true doar daca s-a scazut efectiv.
*
* De ce exista: pana acum cheltuirea era imprastiata in ~11 locuri, iar
* o parte scriau ABSOLUT ("gold = $session->gold - 2"). Scrierea absoluta
* porneste de la soldul din sesiune, care poate fi vechi de pana la 30 de
* secunde (cache-ul din Session::PopulateVar) - de aici riscul de dubla
* cheltuire pe care il semnalau si comentariile din Building.php si
* build.php. Scaderea relativa nu are problema asta.
*
* NU verifica permisiunile de sitter: gardul se pune in stratul de mai sus,
* unde exista context pentru mesajul de eroare si pentru redirect.
*/
function spendGold($uid, $amount, $reason = '') {
$uid = (int) $uid;
$amount = (int) $amount;
if ($uid <= 0 || $amount <= 0) {
return false;
}
$q = "UPDATE " . TB_PREFIX . "users SET gold = gold - " . $amount
. " WHERE id = " . $uid . " AND gold >= " . $amount;
mysqli_query($this->dblink, $q);
if (mysqli_affected_rows($this->dblink) != 1) {
return false;
}
// soldul s-a schimbat in baza de date; cache-ul de sesiune trebuie
// invalidat, altfel urmatoarea cerere ar reciti vechea valoare
if (isset($_SESSION['username'])) {
unset($_SESSION['cache_user_' . $_SESSION['username']]);
}
return true;
}
function modifyGold($userid, $amt, $mode) {
list($userid, $amt, $mode) = $this->escape_input((int) $userid, (int) $amt, $mode);
+10
View File
@@ -4383,3 +4383,13 @@ tz_def('HERO_HEADER_RETURN_HOME', 'Hero returning home');
tz_def('HERO_HEADER_PER_HOUR', 'per hour');
tz_def('TZ_HEALTH', 'Health');
//////////////////////////////////////////////////////////////////////////////////////////////////////
// PERMISIUNI SITTER
//////////////////////////////////////////////////////////////////////////////////////////////////////
tz_def('SITTER_P_ATTACK', 'send attacks');
tz_def('SITTER_P_RAID', 'send raids');
tz_def('SITTER_P_REINF', 'send reinforcements');
tz_def('SITTER_P_RES', 'send resources to other players');
tz_def('SITTER_P_GOLD', 'spend Gold');
tz_def('SITTER_P_DENIED', 'Your sitter permissions do not allow this action.');
+10
View File
@@ -4325,3 +4325,13 @@ tz_def('HERO_HEADER_RETURN_ADV', 'Le heros revient de l\'aventure');
tz_def('HERO_HEADER_RETURN_HOME', 'Le heros rentre chez lui');
tz_def('HERO_HEADER_PER_HOUR', 'par heure');
tz_def('TZ_HEALTH', 'Sante');
//////////////////////////////////////////////////////////////////////////////////////////////////////
// PERMISSIONS DU SITTER
//////////////////////////////////////////////////////////////////////////////////////////////////////
tz_def('SITTER_P_ATTACK', 'envoyer des attaques');
tz_def('SITTER_P_RAID', 'envoyer des raids');
tz_def('SITTER_P_REINF', 'envoyer des renforts');
tz_def('SITTER_P_RES', 'envoyer des ressources à dautres joueurs');
tz_def('SITTER_P_GOLD', 'dépenser de lor');
tz_def('SITTER_P_DENIED', 'Vos permissions de sitter ne vous permettent pas deffectuer cette action.');
+11
View File
@@ -4119,3 +4119,14 @@ tz_def('HERO_HEADER_ATTACK', 'Eroul este plecat cu armata');
tz_def('HERO_HEADER_REINFORCE', 'Eroul este intr-o intarire');
tz_def('HERO_HEADER_IN', 'in');
tz_def('TZ_HEALTH', 'Sanatate');
//////////////////////////////////////////////////////////////////////////////////////////////////////
// PERMISIUNI SITTER
//////////////////////////////////////////////////////////////////////////////////////////////////////
tz_def('SITTER_P_ATTACK', 'trimite atacuri');
tz_def('SITTER_P_RAID', 'trimite raiduri');
tz_def('SITTER_P_REINF', 'trimite intariri');
tz_def('SITTER_P_RES', 'trimite resurse altor jucatori');
tz_def('SITTER_P_GOLD', 'cheltuie aur');
tz_def('SITTER_P_DENIED', 'Permisiunile tale de sitter nu iti permit aceasta actiune.');
+60 -2
View File
@@ -290,9 +290,50 @@ class Market
// Keeping logic safe while preserving compatibility.
$id = isset($post['getwref']) ? (int)$post['getwref'] : 0;
// Check vacation mode
/**
* PERMISIUNI SITTER: "trimite resurse altor jucatori".
*
* Restrictia se aplica DOAR catre alte conturi. Mutarea resurselor
* intre satele proprii ramane permisa - altfel un sitter n-ar mai putea
* administra contul deloc, ceea ce nu e scopul.
*
* Verificam proprietarul satului tinta, nu numele lui: un jucator poate
* avea oricate sate, iar comparatia pe uid e singura de incredere.
*/
if ($id > 0 && isset($session) && is_object($session) && method_exists($session, 'sitterCan')) {
$targetOwner = (int) $database->getVillageField($id, 'owner');
if ($targetOwner > 0
&& $targetOwner !== (int) $session->uid
&& !$session->sitterCan(SITTER_PERM_RES)) {
$form->addError('error', defined('SITTER_P_DENIED')
? SITTER_P_DENIED
: 'Your sitter permissions do not allow this action.');
/**
* "return", nu doar addError: mai jos urmeaza un lant
* if/elseif care ajunge la ramura de trimitere indiferent de
* erorile adaugate inainte. Fara iesire explicita, resursele
* ar fi plecat oricum, iar mesajul de eroare ar fi fost doar
* decorativ.
*/
return;
}
}
/**
* BUG PREEXISTENT: modul vacanta era doar semnalat, nu si blocat.
*
* Eroarea se adauga aici, dar mai jos urmeaza un lant if/elseif care
* ajunge la ramura de trimitere indiferent de erorile de dinainte.
* Rezultatul: mesajul "utilizatorul e in vacanta" aparea pe ecran, dar
* resursele plecau oricum catre contul protejat. Iesim explicit.
*/
if ($database->getvacmodexy($id)) {
$form->addError('error', USER_ON_VACATION);
return;
}
if (!$database->checkVilExist($post['getwref'])) {
@@ -878,6 +919,21 @@ class Market
exit;
}
/**
* PERMISIUNI SITTER: schimbul NPC costa 3 aur.
*
* Gardul TREBUIE sa fie aici, nu langa plata de la finalul functiei:
* redistribuirea resurselor (setVillageField) se executa INAINTE de
* scaderea aurului, deci un garda pus doar pe plata ar fi oferit
* sitterului NPC gratuit.
*/
if (isset($session) && method_exists($session, 'sitterCan')
&& !$session->sitterCan(SITTER_PERM_GOLD)) {
header('Location: build.php?id=' . $post['id'] . '&t=3');
exit;
}
// Sanitize the requested distribution: never negative, never above the
// warehouse / granary capacity. Guards against a forged or NaN-corrupted
// POST (issue #211: NPC distribution).
@@ -917,7 +973,9 @@ class Market
]
);
$this->forget();
$database->modifyGold($session->uid, 3, 0);
// permisiunea a fost verificata la intrarea in functie
$database->spendGold($session->uid, 3, 'NPC merchant');
header('Location: build.php?id=' . $post['id'] . '&t=3&c');
exit;
+65
View File
@@ -448,6 +448,31 @@ class Profile {
}
}
/**
* Transforma un set de casute bifate intr-o masca de biti.
*
* Acceptam doar valorile din SITTER_PERM_ALL: orice altceva venit prin
* POST e ignorat, ca un jucator sa nu-si poata inventa biti noi.
* Un array gol inseamna "niciun drept" - stare perfect valida, deci NU
* cadem pe SITTER_PERM_ALL cand lipseste continutul.
*/
$sitterMaskFromPost = function ($raw) {
$mask = 0;
if (is_array($raw)) {
foreach ($raw as $bit) {
$bit = (int) $bit;
if ($bit > 0 && ($bit & SITTER_PERM_ALL) === $bit) {
$mask |= $bit;
}
}
}
return $mask;
};
// Sitter assignment
if (!empty($post['v1'])) {
@@ -458,15 +483,55 @@ class Profile {
} else if ($sitid != $session->uid) {
// permisiunile cu care intra noul sitter
$newPerm = $sitterMaskFromPost($post['perm_new'] ?? null);
if ($session->userinfo['sit1'] == 0) {
$database->updateUserField($session->uid, "sit1", $sitid, 1);
$database->updateUserField($session->uid, "sit1_perm", $newPerm, 1);
} else if ($session->userinfo['sit2'] == 0) {
$database->updateUserField($session->uid, "sit2", $sitid, 1);
$database->updateUserField($session->uid, "sit2_perm", $newPerm, 1);
}
}
}
/**
* Actualizarea permisiunilor pentru sitterii deja existenti.
*
* Casutele sunt in acelasi formular cu restul setarilor de cont, deci
* ajung aici la orice salvare. Scriem doar pentru sloturile ocupate -
* altfel am seta permisiuni pentru un sitter inexistent.
*
* Atentie: casutele nebifate NU se trimit prin POST. De aceea ne uitam
* dupa cheia campului, nu dupa continutul ei: daca perm1 lipseste cu
* totul inseamna ca formularul nu continea sectiunea (nu ca sitterul
* si-a pierdut toate drepturile).
*/
foreach (array(1 => 'sit1', 2 => 'sit2') as $slot => $key) {
if ((int) $session->userinfo[$key] === 0) {
continue;
}
$field = 'perm' . $slot;
// slotul e afisat in formular doar cand e ocupat; daca butonul de
// salvare a fost apasat, campul exista chiar si gol (vezi hidden-ul
// din account.tpl)
if (!isset($post[$field . '_sent'])) {
continue;
}
$database->updateUserField(
$session->uid,
$key . '_perm',
$sitterMaskFromPost($post[$field] ?? null),
1
);
}
// Persist errors if any
if ($form->returnErrors() > 0) {
$_SESSION['errorarray'] = $form->getErrors();
+121 -1
View File
@@ -1,5 +1,17 @@
<?php
/**
* Permisiuni sitter - masca de biti. Definite aici, nu in config, ca sa fie
* disponibile oriunde e incarcat Session.php (adica pe orice pagina de joc).
*/
if (!defined('SITTER_PERM_ATTACK')) define('SITTER_PERM_ATTACK', 1);
if (!defined('SITTER_PERM_RAID')) define('SITTER_PERM_RAID', 2);
if (!defined('SITTER_PERM_REINF')) define('SITTER_PERM_REINF', 4);
if (!defined('SITTER_PERM_RES')) define('SITTER_PERM_RES', 8);
if (!defined('SITTER_PERM_GOLD')) define('SITTER_PERM_GOLD', 16);
if (!defined('SITTER_PERM_ALL')) define('SITTER_PERM_ALL', 31);
#################################################################################
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
## --------------------------------------------------------------------------- ##
@@ -94,6 +106,26 @@ class Session {
var $sit;
var $sit1;
var $sit2;
/**
* PERMISIUNI SITTER (masca de biti, salvata in users.sit1_perm / sit2_perm)
*
* 1 SITTER_PERM_ATTACK - trimite atacuri normale
* 2 SITTER_PERM_RAID - trimite raiduri
* 4 SITTER_PERM_REINF - trimite intariri
* 8 SITTER_PERM_RES - trimite resurse altor jucatori
* 16 SITTER_PERM_GOLD - cheltuie aur
* 31 SITTER_PERM_ALL - toate (valoarea implicita)
*
* 31 e default in baza de date ca sitterii existenti sa nu-si piarda
* drepturile in momentul migrarii.
*/
/** uid-ul sitterului conectat; 0 = sesiune normala, a proprietarului */
public $sitterUid = 0;
/** masca de permisiuni valabila pentru sesiunea curenta */
public $sitterPerm = 31;
var $cp;
function __construct() {
global $database;
@@ -511,10 +543,59 @@ function __construct() {
$this->checker = $_SESSION['checker'];
$this->mchecker = $_SESSION['mchecker'];
$this->sit = $database->GetOnline($this->uid);
/**
* $this->sit (0 = proprietar, 1 = sitter) se calculeaza acum din
* sesiune, nu din tabela "online".
*
* GetOnline() citea flagul scris de UpdateOnline() cu INSERT IGNORE -
* adica flagul NU se actualiza daca randul exista deja. In practica:
* - proprietarul care se loga dupa un sitter mostenea sit = 1 si era
* blocat sa cumpere Plus pe propriul cont;
* - sitterul care se loga dupa proprietar primea sit = 0 si trecea de
* toate gardurile.
* Flagul din sesiune e per-sesiune si mereu corect, deci il folosim ca
* sursa. Toti consumatorii existenti de $session->sit (a2b.php,
* alli_menu.tpl, Profile/overview.tpl, Templates/Plus/*) se repara
* automat, fara sa fie atinsi.
*
* Nota: sesiunile deschise INAINTE de acest update nu au sitter_uid,
* deci un sitter deja conectat va aparea ca proprietar pana la
* urmatoarea autentificare.
*/
$this->sit = (isset($_SESSION['sitter_uid']) && (int) $_SESSION['sitter_uid'] > 0) ? 1 : 0;
$this->sit1 = $this->userarray['sit1'];
$this->sit2 = $this->userarray['sit2'];
/**
* Permisiunile sesiunii curente.
*
* Recitim sit1/sit2 din contul proprietarului la FIECARE cerere, nu
* doar la login: daca proprietarul retrage un sitter sau ii taie un
* drept in timp ce acesta e conectat, modificarea se aplica imediat.
*
* Daca sitterul conectat nu mai apare in sit1/sit2 (a fost sters
* intre timp), masca devine 0 - adica nu mai are voie nimic.
*/
$this->sitterUid = isset($_SESSION['sitter_uid']) ? (int) $_SESSION['sitter_uid'] : 0;
$this->sitterPerm = SITTER_PERM_ALL;
if ($this->sitterUid > 0) {
if ((int) $this->userarray['sit1'] === $this->sitterUid) {
$this->sitterPerm = isset($this->userarray['sit1_perm'])
? (int) $this->userarray['sit1_perm']
: SITTER_PERM_ALL;
} else if ((int) $this->userarray['sit2'] === $this->sitterUid) {
$this->sitterPerm = isset($this->userarray['sit2_perm'])
? (int) $this->userarray['sit2_perm']
: SITTER_PERM_ALL;
} else {
$this->sitterPerm = 0;
}
}
$this->cp = floor($this->userarray['cp']);
$this->gold = $this->userarray['gold'];
$this->oldrank = $this->userarray['oldrank'];
@@ -606,6 +687,45 @@ function __construct() {
}
}
}
/**
* Sesiunea curenta apartine unui sitter, nu proprietarului contului?
*/
public function isSitterSession()
{
return $this->sitterUid > 0;
}
/**
* Are sesiunea curenta dreptul $perm (una din constantele SITTER_PERM_*)?
*
* Proprietarul primeste mereu true. Se verifica la EXECUTIE, pe server -
* nu e suficient sa ascunzi butoanele, fiindca un sitter poate trimite
* POST-ul direct.
*/
/**
* Scurtatura pentru cel mai des folosit drept.
* Intoarce mesajul de eroare gata de afisat, sau "" daca are voie.
*/
public function sitterGoldError()
{
if ($this->sitterCan(SITTER_PERM_GOLD)) {
return "";
}
return defined('SITTER_P_DENIED')
? SITTER_P_DENIED
: 'Your sitter permissions do not allow this action.';
}
public function sitterCan($perm)
{
if (!$this->isSitterSession()) {
return true;
}
return ((int) $this->sitterPerm & (int) $perm) === (int) $perm;
}
}
$session = new Session;
+71
View File
@@ -76,6 +76,47 @@ class Units {
* @return string Returns the errors, or empty if no errors was found
*/
/**
* PERMISIUNI SITTER - misiune -> drept necesar.
*
* Codurile de misiune vin din formularul de trimitere (Templates/a2b/):
* 1 = spionaj -> permis mereu (nu e in lista din Travian)
* 2 = intarire -> SITTER_PERM_REINF
* 3 = atac normal -> SITTER_PERM_ATTACK
* 4 = raid -> SITTER_PERM_RAID
* 5 = colonizare -> permis mereu
*
* Intoarce mesajul de eroare, sau "" daca actiunea e permisa.
* Proprietarul contului primeste mereu "".
*/
private function sitterMissionError($missionType) {
global $session;
if (!isset($session) || !is_object($session) || !method_exists($session, 'sitterCan')) {
return "";
}
$map = array(
2 => SITTER_PERM_REINF,
3 => SITTER_PERM_ATTACK,
4 => SITTER_PERM_RAID,
);
$missionType = (int) $missionType;
if (!isset($map[$missionType])) {
return "";
}
if ($session->sitterCan($map[$missionType])) {
return "";
}
return defined('SITTER_P_DENIED')
? SITTER_P_DENIED
: 'Your sitter permissions do not allow this action.';
}
public function checkErrors(&$post){
global $database, $generator, $session;
@@ -87,6 +128,9 @@ class Units {
if(!empty($disabled) && $post['c'] == 3) return "You can't attack this village/oasis with normal attack";
if($post['c'] < 2 || $post['c'] > 4) return "Invalid attack type.";
// sitterul fara dreptul respectiv nu ajunge nici macar la confirmare
if(($error = $this->sitterMissionError($post['c'])) !== "") return $error;
//check if at least one troops has been selected
$selectedTroops = 0;
for($i = 1; $i <= 11; $i++) $selectedTroops += empty($post['t'.$i]) ? 0 : $post['t'.$i];
@@ -344,6 +388,22 @@ class Units {
$data = $database->getA2b($post['timestamp_checksum']);
$Gtribe = ($session->tribe == 1) ? "" : $session->tribe - 1;
/**
* A DOUA verificare, cea care conteaza cu adevarat.
*
* checkErrors() ruleaza pe formular, dar un sitter poate trimite POST-ul
* de confirmare direct, sarind peste el. Aici e ultimul punct inainte ca
* trupele sa fie scazute din sat, deci verificam din nou - pe tipul REAL
* al misiunii, citit din baza de date ($data['type']), nu din $_POST.
*/
if (($sitterError = $this->sitterMissionError($data['type'] ?? 0)) !== "") {
$form->addError("error", $sitterError);
$_SESSION['errorarray'] = $form->getErrors();
$_SESSION['valuearray'] = $_POST;
header("Location: a2b.php");
exit;
}
for ($i = 1; $i < 10; $i++) {
if (isset($data['u'.$i])) {
if ($data['u'.$i] > $village->unitarray['u'.$Gtribe.$i]) {
@@ -965,6 +1025,17 @@ class Units {
public function startRaidList($post){
global $database, $generator, $session;
/**
* Lista de ferme trimite raiduri, deci intra tot sub SITTER_PERM_RAID.
* Fara garda aici, un sitter caruia i s-ai taiat raidurile le-ar fi
* putut porni oricum din Punctul de Adunare.
*/
if (($sitterError = $this->sitterMissionError(4)) !== "") {
$_SESSION['errorarray'] = array($sitterError);
header("Location: build.php?id=39&t=99");
exit();
}
$slots = $post['slot'] ?? [];
if(empty($slots)){
header("Location: build.php?id=39&t=99");
+5 -1
View File
@@ -18,7 +18,11 @@
## --------------------------------------------------------------------------- ##
#################################################################################
if($session->sit == 0) {
// PERMISIUNI SITTER: cumparaturile cu aur.
// Inlocuieste vechiul "$session->sit", care citea un flag din tabela online
// scris cu INSERT IGNORE - deci nu se actualiza daca randul exista deja.
// sitterCan() se bazeaza pe sesiune, deci e mereu corect.
if($session->sitterCan(SITTER_PERM_GOLD)) {
$uid = (int)$session->uid;
$wid = (int)$village->wid;
$now = time();
+5 -1
View File
@@ -18,7 +18,11 @@
## --------------------------------------------------------------------------- ##
#################################################################################
if($session->sit == 0) {
// PERMISIUNI SITTER: cumparaturile cu aur.
// Inlocuieste vechiul "$session->sit", care citea un flag din tabela online
// scris cu INSERT IGNORE - deci nu se actualiza daca randul exista deja.
// sitterCan() se bazeaza pe sesiune, deci e mereu corect.
if($session->sitterCan(SITTER_PERM_GOLD)) {
$uid = (int)$session->uid;
$wid = (int)$village->wid;
$now = time();
+5 -1
View File
@@ -18,7 +18,11 @@
## --------------------------------------------------------------------------- ##
#################################################################################
if($session->sit == 0) {
// PERMISIUNI SITTER: cumparaturile cu aur.
// Inlocuieste vechiul "$session->sit", care citea un flag din tabela online
// scris cu INSERT IGNORE - deci nu se actualiza daca randul exista deja.
// sitterCan() se bazeaza pe sesiune, deci e mereu corect.
if($session->sitterCan(SITTER_PERM_GOLD)) {
$uid = (int)$session->uid;
$wid = (int)$village->wid;
$now = time();
+5 -1
View File
@@ -24,7 +24,11 @@ $wid = (int)$village->wid;
$now = time();
$cost = 100;
if($session->sit != 0) {
// PERMISIUNI SITTER: cumparaturile cu aur.
// Inlocuieste vechiul "$session->sit", care citea un flag din tabela online
// scris cu INSERT IGNORE - deci nu se actualiza daca randul exista deja.
// sitterCan() se bazeaza pe sesiune, deci e mereu corect.
if(!$session->sitterCan(SITTER_PERM_GOLD)) {
header("Location: plus.php?id=3"); exit;
}
+5 -1
View File
@@ -18,7 +18,11 @@
## --------------------------------------------------------------------------- ##
#################################################################################
if($session->sit == 0) {
// PERMISIUNI SITTER: cumparaturile cu aur.
// Inlocuieste vechiul "$session->sit", care citea un flag din tabela online
// scris cu INSERT IGNORE - deci nu se actualiza daca randul exista deja.
// sitterCan() se bazeaza pe sesiune, deci e mereu corect.
if($session->sitterCan(SITTER_PERM_GOLD)) {
$now = time();
$uid = (int)$session->uid;
$wid = (int)$village->wid;
+5 -1
View File
@@ -18,7 +18,11 @@
## --------------------------------------------------------------------------- ##
#################################################################################
if($session->sit == 0) {
// PERMISIUNI SITTER: cumparaturile cu aur.
// Inlocuieste vechiul "$session->sit", care citea un flag din tabela online
// scris cu INSERT IGNORE - deci nu se actualiza daca randul exista deja.
// sitterCan() se bazeaza pe sesiune, deci e mereu corect.
if($session->sitterCan(SITTER_PERM_GOLD)) {
$uid = (int)$session->uid;
$wid = (int)$village->wid;
$now = time();
+17
View File
@@ -46,6 +46,23 @@ if(empty($_POST['plus'])) {
</form>
<?php
} else {
/**
* PERMISIUNI SITTER: aici se cumpara Plus si bonusurile de productie.
*
* Acest sablon nu avea NICIO verificare de sitter - spre deosebire de
* 8/9/10/11/12/15.tpl, care aveau (chiar daca pe un flag nesigur). Un
* sitter putea cheltui aurul proprietarului de aici, oricat.
*/
if (isset($session) && method_exists($session, 'sitterCan')
&& !$session->sitterCan(SITTER_PERM_GOLD)) {
die('<div align="center"><font color="red"><b>'
. (defined('SITTER_P_DENIED') ? SITTER_P_DENIED
: 'Your sitter permissions do not allow this action.')
. '</b></font><br><button onclick="history.back()">' . BACK . '</button></div>');
}
$reward = $_POST['reward'] ?? '';
// whitelist
+67
View File
@@ -32,6 +32,48 @@ $sitterError = $form->getError("sit");
$count = 0;
if ($session->userinfo['sit1'] != 0) $count += 1;
if ($session->userinfo['sit2'] != 0) $count += 1;
/**
* PERMISIUNI SITTER
*
* Lista e definita o singura data si folosita si la sitterii existenti, si la
* casuta de adaugare, ca sa nu se desincronizeze. Cheile din $_POST sunt
* perm1[], perm2[] si perm_new[], fiecare continand valorile bitilor bifati.
*/
$sitterPermList = array(
SITTER_PERM_ATTACK => defined('SITTER_P_ATTACK') ? SITTER_P_ATTACK : 'send attacks',
SITTER_PERM_RAID => defined('SITTER_P_RAID') ? SITTER_P_RAID : 'send raids',
SITTER_PERM_REINF => defined('SITTER_P_REINF') ? SITTER_P_REINF : 'send reinforcements',
SITTER_PERM_RES => defined('SITTER_P_RES') ? SITTER_P_RES : 'send resources to other players',
SITTER_PERM_GOLD => defined('SITTER_P_GOLD') ? SITTER_P_GOLD : 'spend Gold',
);
/**
* Casutele pentru un slot. $mask = permisiunile curente, $field = numele
* campului din formular.
*/
function sitterPermBoxes($mask, $field, $list) {
/**
* Marcaj ascuns: o casuta nebifata nu se trimite deloc prin POST, deci
* "toate debifate" ar arata identic cu "sectiunea nu a fost afisata".
* Campul asta e mereu trimis, asa ca Profile.php poate deosebi cele doua
* situatii si nu reseteaza permisiunile din greseala.
*/
$out = '<input type="hidden" name="' . $field . '_sent" value="1" />';
$out .= '<div class="sitterPerm">';
foreach ($list as $bit => $label) {
$checked = (((int) $mask & $bit) === $bit) ? ' checked' : '';
$out .= '<label><input type="checkbox" class="checkbox" name="' . $field . '[]"'
. ' value="' . (int) $bit . '"' . $checked . ' /> '
. htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '</label>';
}
return $out . '</div>';
}
?>
<form action="spieler.php" method="POST">
@@ -110,6 +152,19 @@ if (!empty($emailError)) {
}
?>
<style type="text/css">
/* casutele de permisiuni pentru sitteri */
#sitter .sitterPerm { margin: 4px 0 8px 18px; }
#sitter .sitterPerm label {
display: block;
padding: 1px 0;
font-weight: normal;
white-space: nowrap;
cursor: pointer;
}
#sitter .sitterPerm input { margin-right: 5px; vertical-align: -1px; }
</style>
<!-- =========================
SITTERS
========================= -->
@@ -133,6 +188,10 @@ if (!empty($emailError)) {
<td>
<input class="text" type="text" name="v1" maxlength="15">
<span class="count">(<?php echo $count; ?>/2)</span>
<?php
// permisiunile cu care intra noul sitter; implicit toate bifate
echo sitterPermBoxes(SITTER_PERM_ALL, 'perm_new', $sitterPermList);
?>
</td>
</tr>
<?php } ?>
@@ -160,6 +219,14 @@ foreach ($sitSlots as $type => $key) {
echo "<img class=\"del\" src=\"img/x.gif\" title=\"Remove sitters\" alt=\"Remove sitters\" />";
echo "</a>";
echo "<a href=\"spieler.php?uid=".$uid."\">".$uname."</a>";
// permisiunile curente ale acestui sitter
$permField = 'perm' . $type;
$permMask = isset($session->userinfo[$key . '_perm'])
? (int) $session->userinfo[$key . '_perm']
: SITTER_PERM_ALL;
echo sitterPermBoxes($permMask, $permField, $sitterPermList);
echo "</div>";
}
}
+20 -10
View File
@@ -116,8 +116,15 @@ if ( isset( $_GET['id'] ) ) {
if ($session->goldclub == 1 && count($session->villages) > 1) {
if (isset($_POST['routeid'])) $routeid = $_POST['routeid'];
/**
* PERMISIUNI SITTER: rutele comerciale costa 2 aur (creare si prelungire).
* Gardul e aici, inaintea ambelor actiuni, nu in fiecare ramura.
*/
$sitterGoldBlocked = (isset($session) && method_exists($session, 'sitterCan')
&& !$session->sitterCan(SITTER_PERM_GOLD));
if (isset($_POST['action']) && $_POST['action'] == 'addRoute') {
if ($session->gold >= 2 && $session->goldclub == 1) {
if ($session->gold >= 2 && $session->goldclub == 1 && !$sitterGoldBlocked) {
for ($i = 1; $i <= 4; $i ++) {
if (empty($_POST['r'.$i])) $_POST['r'.$i] = 0;
}
@@ -147,17 +154,20 @@ if ($session->goldclub == 1 && count($session->villages) > 1) {
}
if (isset($_POST['routeid']) && isset($_POST['action']) && $_POST['action'] == 'extendRoute') {
if ($session->gold >= 2 && $session->goldclub == 1) {
if ($session->gold >= 2 && $session->goldclub == 1 && !$sitterGoldBlocked) {
$traderoute = $database->getTradeRouteUid($_POST['routeid']);
if ($traderoute == $session->uid) {
$database->editTradeRoute($_POST['routeid'], "timeleft", 604800, 1);
$newgold = $session->gold - 2;
$database->updateUserField($session->uid, 'gold', $newgold, 1);
$session->gold = $newgold;
// Invalidate the 30s session user-cache (see Session::PopulateVar) so
// the gold balance is fresh next request; the write is absolute
// ($session->gold - 2), so a stale cache could double-spend.
unset($_SESSION['cache_user_' . ($_SESSION['username'] ?? '')]);
/**
* spendGold() scade relativ si atomic, apoi invalideaza singur
* cache-ul de sesiune. Inainte se scria absolut pornind de la
* $session->gold, care putea fi vechi de 30 de secunde - exact
* riscul de dubla cheltuire semnalat in comentariul de aici.
* Prelungirea se face DOAR daca plata a reusit.
*/
if ($database->spendGold($session->uid, 2, 'Extend trade route')) {
$database->editTradeRoute($_POST['routeid'], "timeleft", 604800, 1);
$session->gold -= 2;
}
}
}
$route = 1;
+2
View File
@@ -1995,7 +1995,9 @@ CREATE TABLE IF NOT EXISTS `%PREFIX%users` (
`b3` int(11) DEFAULT '0',
`b4` int(11) DEFAULT '0',
`sit1` int(11) DEFAULT '0',
`sit1_perm` int(11) NOT NULL DEFAULT '31',
`sit2` int(11) DEFAULT '0',
`sit2_perm` int(11) NOT NULL DEFAULT '31',
`alliance` int(11) DEFAULT '0',
`alliance_joined` int(11) NOT NULL DEFAULT '0',
`sessid` varchar(100) DEFAULT NULL,