class wfJWT {
private $claims;
const JWT_TTL = 600;
const ISSUER = 600;
public static function extractTokenContents($token) {
if (!is_string($token)) {
throw new InvalidArgumentException('Token is not a string. ' . gettype($token) . ' given.');
}
// Verify the token matches the JWT format.
if (!preg_match('/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?$/', $token)) {
throw new wfJWTException('Invalid token format.');
}
list($header, $body, $signature) = explode('.', $token);
// Test that the token is valid and not expired.
$decodedHeader = base64_decode($header);
if (!(is_string($decodedHeader) && $decodedHeader)) {
throw new wfJWTException('Token header is invalid.');
}
$header = json_decode($decodedHeader, true);
if (!is_array($header)) {
throw new wfJWTException('Token header is invalid.');
}
$decodedBody = base64_decode($body);
if (!(is_string($decodedBody) && $decodedBody)) {
throw new wfJWTException('Token body is invalid.');
}
$body = json_decode($decodedBody, true);
if (!is_array($body)) {
throw new wfJWTException('Token body is invalid.');
}
return array(
'header' => $header,
'body' => $body,
'signature' => $signature,
);
}
/**
* @param mixed $subject
*/
public function __construct($subject = null) {
$this->claims = $this->getClaimDefaults();
$this->claims['sub'] = $subject;
}
/**
* @return string
*/
public function encode() {
$header = $this->encodeString($this->buildHeader());
$body = $this->encodeString($this->buildBody());
return sprintf('%s.%s.%s', $header, $body,
$this->encodeString($this->sign(sprintf('%s.%s', $header, $body))));
}
/**
* @param string $token
* @return array
* @throws wfJWTException|InvalidArgumentException
*/
public function decode($token) {
if (!is_string($token)) {
throw new InvalidArgumentException('Token is not a string. ' . gettype($token) . ' given.');
}
// Verify the token matches the JWT format.
if (!preg_match('/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?$/', $token)) {
throw new wfJWTException('Invalid token format.');
}
list($header, $body, $signature) = explode('.', $token);
// Verify signature matches the supplied payload.
if (!$this->verifySignature($this->decodeString($signature), sprintf('%s.%s', $header, $body))) {
throw new wfJWTException('Invalid signature.');
}
// Test that the token is valid and not expired.
$decodedHeader = base64_decode($header);
if (!(is_string($decodedHeader) && $decodedHeader)) {
throw new wfJWTException('Token header is invalid.');
}
$header = json_decode($decodedHeader, true);
if (!(
is_array($header) &&
array_key_exists('alg', $header) &&
$header['alg'] === 'HS256' &&
$header['typ'] === 'JWT'
)) {
throw new wfJWTException('Token header is invalid.');
}
$decodedBody = base64_decode($body);
if (!(is_string($decodedBody) && $decodedBody)) {
throw new wfJWTException('Token body is invalid.');
}
$body = json_decode($decodedBody, true);
if (!(
is_array($body) &&
// Check the token not before now timestamp.
array_key_exists('nbf', $body) &&
is_numeric($body['nbf']) &&
$body['nbf'] <= time() &&
// Check the token is not expired.
array_key_exists('exp', $body) &&
is_numeric($body['exp']) &&
$body['exp'] >= time() &&
// Check the issuer and audience is ours.
$body['iss'] === 'Wordfence ' . WORDFENCE_VERSION &&
$body['aud'] === 'Wordfence Central'
)) {
throw new wfJWTException('Token is invalid or expired.');
}
return array(
'header' => $header,
'body' => $body,
);
}
/**
* @param string $string
* @return string
*/
public function sign($string) {
$salt = wp_salt('auth');
return hash_hmac('sha256', $string, $salt, true);
}
/**
* @param string $signature
* @param string $message
* @return bool
*/
public function verifySignature($signature, $message) {
return hash_equals($this->sign($message), $signature);
}
/**
* @return string
*/
public function __toString() {
return $this->encode();
}
/**
* @param string $data
* @return string
*/
public function encodeString($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
/**
* @param string $data
* @return bool|string
*/
public function decodeString($data) {
return base64_decode(strtr($data, '-_', '+/'));
}
/**
* @return mixed|string
*/
protected function buildHeader() {
return '{"alg":"HS256","typ":"JWT"}';
}
/**
* @return mixed|string
*/
protected function buildBody() {
return json_encode($this->getClaims());
}
/**
* @return array
*/
protected function getClaimDefaults() {
$now = time();
return array(
'iss' => 'Wordfence ' . WORDFENCE_VERSION,
'aud' => 'Wordfence Central',
'nbf' => $now,
'iat' => $now,
'exp' => $now + self::JWT_TTL,
);
}
/**
* @param array $claims
*/
public function addClaims($claims) {
if (!is_array($claims)) {
throw new InvalidArgumentException(__METHOD__ . ' expects argument 1 to be array.');
}
$this->setClaims(array_merge($this->getClaims(), $claims));
}
/**
* @return array
*/
public function getClaims() {
return $this->claims;
}
/**
* @param array $claims
*/
public function setClaims($claims) {
$this->claims = $claims;
}
}
class wfJWTException extends Exception {
}
Political chaos brings colossal transformation | Right Tactics
Political chaos brings colossal transformation
Today’s guest is Martin Gurri , a former CIA analyst who is a visiting fellow at the Mercatus Center and a columnist for The Free Press . A decade ago, in the wake of the Arab Spring and various “color” revolutions around the world, Gurri published The Revolt of the Public and the Crisis of Authority in the New Millennium , which analyzed how social media empowered ordinary people to resist control from above and anticipated the rise of Donald Trump, French President Emmanuel Macron, and Brexit.
Reason ‘s Nick Gillespie spoke with Gurri shortly after the 2024 election at The Reason Speakeasy , a monthly, unscripted conversation in New York City with outspoken defenders of free thinking and heterodoxy in an age of intellectual conformity and groupthink. (Go here for information on Reason events.) They talked about why Gurri voted for Trump and why he’s cautiously optimistic about the next four years.
0:00- Introduction
1:13- Why Gurri voted for Trump
4:46- Trump vs. Harris: Chaos vs. Control
8:40- Trump’s first term 11:04- Trump’s new coalition
14:33- Is authoritarianism coming to America?
19:00- Attention, Populism & Wild Hair
20:42- Colossal transformation awaits us
34:05- Creating communities of meaning in the digital age
36:22- The transformations enabled by the printing press
38:41- More chaos is coming 43:11- Lessons from Cuba
48:40- Arab Spring and the spark that overthrows a regime
50:37- Short term pessimistic, long term optimistic
Today’s Sponsor:
Reason Versus: “You Don’t Have To Pick a Side in Politics “: On Wednesday, December 18, you are invited to join Reason and our friends at The Bulwark for this new thought-provoking debate series in Washington D.C. at the Howard Theatre. Whether you’ve made up your mind about the necessity of choosing sides or are questioning the whole premise, this debate will challenge your assumptions and broaden your perspective.