Ben's Blog

miscellaneous ben May 13, 2020

Umbrella Flight Trials

miscellaneous ben May 13, 2020

Vermonting Toddler

 

agriculture, self sustainability ben April 26, 2020

107

Adding a few every year, I didn’t see it coming. But it turns out we planted our 100th blueberry plant this year for a grand total of 107. They’re all still fairly small but they’re growing exponentially and it’s clear that we’ll have an overabundance in a year or 2.

agriculture, self sustainability ben April 21, 2020

Feeling Wealthy in Uncertain Times

We just received a massive pile of compost, behind this is a massive pile of wood chips. Both of which are gold for growers, and so we get to be generous with our plants.

We ordered 18 yards of compost, I learned another completely insane measure: the yard. The amount of hand waving I see when talking about yards is peculiar. Trying to make sense of it online yields the same written hand waving. A cubic yard is a cubic yard, let’s consider ourselves lucky it’s cubic and not using the 11th dimension.

Here’s one thing I love about the U.S. system of measures, it encourages generosity. Because no one has but a vague idea what a cord, a bushel, or a yard is, we over-give to make sure we gave enough.

 

We received the plants we ordered this year. As always we’ll grow our operation a little. They’ll go in the ground as soon as tomorrow. 7 more fruit trees and a bunch more berries.

 

I built more proper shelves in the green house, Nicole is growing the garden significantly. Everything is about to explode in growth.

building, self sustainability ben April 14, 2020

Trenching for Fiber

In preparation for a fiber drop, I buried conduit from the pole to the solar shed. I had never done anything like this before, adding to the long list of skills I’m happy to have.

 

The part in the woods was super hard, I tried to do it by hand but there was no going through the roots. I ended up chainsawing a path for the tractor. With this and some crazy maneuvering, the trench was dug.

The tractor was invaluable to the operation. It always blows my mind how hard it is to move dirt by hand.

Lego / Duplo ben April 11, 2020

Cool Duplo Project #50 – Confinement Focus Measures

maple syrup, self sustainability ben April 02, 2020

Protected: Maple Juice 2020 wrapping up

This content is password-protected. To view it, please enter the password below.

I.T. ben April 02, 2020

PHP Zoom API JWT Bit Banging

It’s always hard to nail the exact sequence when authorizing through a new API. Here’s what I came up with for PHP authorization with Zoom’s JWTs. This is essentially a quick start which gets you enough functions to do a first API call: to list zoom users. Line 40->68 is where the JWt meat happens.

[php]
<?php

// config parameters you need to define
define( ‘ZOOM_TOKEN_FILE’, "/var/.zoom_token" ) ; // some location on the filesystem used to cache your token while it’s current (make sure permissions are restrictive)
define( ‘ZOOM_API_KEY’, "" ) ;
define( ‘ZOOM_API_SECRET’, "" ) ;

// main
print_r( zoom_list_users() ) ;
exit( 0 ) ;

// functions
function zoom_list_users() {
$users = array() ;

$page_number = 1 ;
$keep_going = true ;
while( $keep_going && $page_number<10000 ) {
$result = zoom_make_api_call( "GET", "https://api.zoom.us/v2/users", array(‘page_size’=>300, ‘page_number’=>$page_number, ‘status’=>"active") ) ;
$result = json_decode( $result, true ) ;
if( array_key_exists(‘users’, $result) &&
count($result[‘users’])>0 ) {
foreach( $result[‘users’] as $user ) {
$users[] = $user ;
}
$page_number++ ;
if( $page_number>$result[‘page_count’] ) {
$keep_going = false ;
}
} else {
$keep_going = false ;
}
}

return $users ;
}

// PHP’s default base64 encode isn’t URL safe which messes up the JWT, we need these functions instead
function base64_url_encode( $data ) {
return rtrim( strtr(base64_encode($data), ‘+/’, ‘-_’), ‘=’ ) ;
}
function base64_url_decode( $data ) {
return base64_decode( str_pad(strtr($data, ‘-_’, ‘+/’), strlen($data) % 4, ‘=’, STR_PAD_RIGHT) ) ;
}

function get_token( $refresh=false ) {
if( $refresh===false &&
file_exists(ZOOM_TOKEN_FILE) ) {
return file_get_contents( ZOOM_TOKEN_FILE ) ;
}

$jwt_request_date = @date( "U" ) ; // no warning, proper system timezone assumed
$jwt_expiration_date = $jwt_request_date + 60*60 ; # +1 hour
$jwt_header = ‘{"alg":"HS256","typ":"JWT"}’ ;
$jwt_claim_set = ‘{"iss":"’ . ZOOM_API_KEY . ‘","exp":’ . $jwt_expiration_date . ‘}’ ;
$jwt_signature = sign_data( base64_url_encode($jwt_header) . ‘.’ . base64_url_encode($jwt_claim_set), ZOOM_API_SECRET ) ;
$jwt = base64_url_encode( $jwt_header ) . "." . base64_url_encode( $jwt_claim_set ) . "." . base64_url_encode( $jwt_signature ) ;

file_put_contents( ZOOM_TOKEN_FILE, $jwt ) ;
return $jwt ;
}

function sign_data( $data, $key ) {
return hash_hmac( "SHA256" , $data, $key, true) ;
}

function zoom_make_api_call( $request, $url, $get_variables=null, $post_variables=null, $force_refresh_token=false ) {
$ch = curl_init() ;
$token = get_token( $force_refresh_token ) ;

$getfields = "" ;
if( $get_variables!==null && is_array($get_variables) ) {
foreach( $get_variables as $get_variable_key=>$get_variable_value ) {
$getfields .= "&" . urlencode( $get_variable_key ) . "=" . urlencode( $get_variable_value ) ;
}
if( strlen($getfields)>0 ) {
$getfields = "?" . substr( $getfields, 1 ) ;
}
}

curl_setopt( $ch, CURLOPT_URL, "{$url}{$getfields}" ) ;
curl_setopt( $ch, CURLOPT_PORT , 443 ) ;
curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, $request ) ;
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ) ;
if( $post_variables!==null && is_array($post_variables) ) {
$postfields = "" ;
foreach( $post_variables as $post_variable_key=>$post_variable_value ) {
$postfields .= "&" . urlencode( $post_variable_key ) . "=" . urlencode( $post_variable_value ) ;
}
$postfields = substr( $postfields, 1 ) ;
curl_setopt( $ch, CURLOPT_POSTFIELDS, $postfields ) ;
} else if( $post_variables!==null && is_string($post_variables) ) {
curl_setopt( $ch, CURLOPT_POSTFIELDS, $post_variables ) ;
}
curl_setopt( $ch, CURLOPT_HTTPHEADER, array( "authorization: Bearer {$token}",
"content-type: application/json") ) ;

curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ) ;
curl_setopt( $ch, CURLOPT_HEADER, true ) ;

$response = curl_exec( $ch ) ;
curl_close( $ch ) ;

$response = parse_http_response( $response ) ;

if( $response[‘code’]=="200" ||
$response[‘code’]=="204" ||
$response[‘code’]=="404" ) {
return $response[‘body’] ;
} else if( $response[‘code’]=="401" ) { // expired token
if( $force_refresh_token===false ) {
// safe to recurse
return zoom_make_api_call( $request, $url, $get_variables, $post_variables, true ) ;
} else {
echo "ERROR: had an expired token and I tried to refresh it, yet somehow it’s still expired\n" ;
print_r( $response ) ;
exit( 1 ) ;
}
} else {
echo "ERROR: I have no idea what to do with this response from Zoom\n" ;
print_r( $response ) ;
exit( 1 ) ;
}
}

function parse_http_response( $raw_data ) {
$parsed_response = array( ‘code’=>-1, ‘headers’=>array(), ‘body’=>"" ) ;

$raw_data = explode( "\r\n", $raw_data ) ;

$parsed_response[‘code’] = explode( " ", $raw_data[0] ) ;
$parsed_response[‘code’] = $parsed_response[‘code’][1] ;
$i = 1 ;
if( $parsed_response[‘code’]=="100" ) {
$parsed_response[‘code’] = explode( " ", $raw_data[2] ) ;
$parsed_response[‘code’] = $parsed_response[‘code’][1] ;
$i = 3 ;
}

for( ; $i<count($raw_data) ; $i++ ) {
$raw_datum = $raw_data[$i] ;

$raw_datum = trim( $raw_datum ) ;
if( $raw_datum!="" ) {
if( substr_count($raw_datum, ‘:’)>=1 ) {
$raw_datum = explode( ‘:’, $raw_datum, 2 ) ;
$parsed_response[‘headers’][strtolower($raw_datum[0])] = trim( $raw_datum[1] ) ;
} else {
echo "ERROR: we’re in the headers section of parsing an HTTP section and no colon was found for line: {$raw_datum}\n" ;
exit( 1 ) ;
}
} else {
// we’ve moved to the body section
if( ($i+1)<count($raw_data) ) {
for( $j=($i+1) ; $j<count($raw_data) ; $j++ ) {
$parsed_response[‘body’] .= $raw_data[$j] . "\n" ;
}
}

// we don’t need to continue the $i loop
break ;
}
}

return $parsed_response ;
}

?>
[/php]

maple syrup, self sustainability ben March 09, 2020

Protected: Grand Opening

This content is password-protected. To view it, please enter the password below.

nature encounters ben February 19, 2020

Little by little

he ventures out in the woods by himself a bit further every day

Posts pagination

← Previous 1 … 45 46 47 … 119 Next →

This blog is solar powered

Interactive

  • Handwriting Capture
  • Mandalagaba
  • IPv6 link-local to MAC converter
  • IPv6 MAC to link-local converter
  • Markov Text Generation
  • Markov Word Generation
  • Markov Music Generation
  • Duplogrifier
  • Flood Fill Algorithms
  • Homestead Metrics
  • RGB Playground
  • Web Games

Categories

  • aesthetics111
    • plots54
    • specular holography6
  • Books3
  • I.T.202
    • 3D modeling / printing21
    • AI6
    • all out geekery36
    • electronics27
    • homestead automation6
    • maniacal paranoia25
    • plotters49
    • unix / linux29
    • video games4
    • web development29
    • web games3
  • Lego / Duplo67
  • life in the U.S.42
  • miscellaneous202
  • nature encounters114
  • old vinyls3
  • organs2
  • self sustainability560
    • agriculture105
    • apiculture38
    • apple20
    • building131
    • canning3
    • crochet6
    • foraging6
    • hunting10
    • maple syrup47
    • poultry39
    • preserving2
    • solar power28
    • water23
    • wood84
  • trip to a new life6
Theme by Bloompixel. Proudly Powered by WordPress