1b967cddfSBarry Smith 2b967cddfSBarry Smith #include <petscsys.h> 3b967cddfSBarry Smith #include <errno.h> 4b967cddfSBarry Smith #include <sys/types.h> 5b967cddfSBarry Smith #include <sys/socket.h> 6b967cddfSBarry Smith #include <netinet/in.h> 7b967cddfSBarry Smith #include <netinet/tcp.h> 8b967cddfSBarry Smith #include <netdb.h> 9b967cddfSBarry Smith #include <fcntl.h> 10b967cddfSBarry Smith #include <signal.h> 11b967cddfSBarry Smith #include <unistd.h> 12b967cddfSBarry Smith #include <string.h> 13b967cddfSBarry Smith 14b967cddfSBarry Smith #include <openssl/ssl.h> 15b967cddfSBarry Smith #include <openssl/err.h> 16b967cddfSBarry Smith 17b967cddfSBarry Smith static BIO *bio_err = NULL; 18b967cddfSBarry Smith 19b967cddfSBarry Smith #define PASSWORD "password" 20b967cddfSBarry Smith 21b967cddfSBarry Smith #if defined(PETSC_USE_CERTIFICATE) 22b967cddfSBarry Smith static int password_cb(char *buf,int num, int rwflag,void *userdata) 23b967cddfSBarry Smith { 24b967cddfSBarry Smith if (num < strlen(PASSWORD)+1) return(0); 25b967cddfSBarry Smith strcpy(buf,PASSWORD); 26b967cddfSBarry Smith return(strlen(PASSWORD)); 27b967cddfSBarry Smith } 28b967cddfSBarry Smith #endif 29b967cddfSBarry Smith 30b967cddfSBarry Smith static void sigpipe_handle(int x) 31b967cddfSBarry Smith { 32b967cddfSBarry Smith } 33b967cddfSBarry Smith 34b967cddfSBarry Smith #undef __FUNCT__ 35b967cddfSBarry Smith #define __FUNCT__ "PetscSSLInitializeContext" 36b967cddfSBarry Smith /* 37b967cddfSBarry Smith PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests. 38b967cddfSBarry Smith 39b967cddfSBarry Smith If built with PETSC_USE_CERTIFICATE requires the user have created a self-signed certificate with 40b967cddfSBarry Smith 41b967cddfSBarry Smith $ ./CA.pl -newcert (using the passphrase of password) 42b967cddfSBarry Smith $ cat newkey.pem newcert.pem > sslclient.pem 43b967cddfSBarry Smith 44b967cddfSBarry Smith and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of 45b967cddfSBarry Smith silly but it was all I could figure out. 46b967cddfSBarry Smith 47b967cddfSBarry Smith */ 48b967cddfSBarry Smith PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx) 49b967cddfSBarry Smith { 50b967cddfSBarry Smith SSL_METHOD *meth; 51b967cddfSBarry Smith SSL_CTX *ctx; 52b967cddfSBarry Smith #if defined(PETSC_USE_CERTIFICATE) 53b967cddfSBarry Smith char keyfile[PETSC_MAX_PATH_LEN]; 54b967cddfSBarry Smith PetscBool exists; 55b967cddfSBarry Smith PetscErrorCode ierr; 56b967cddfSBarry Smith #endif 57b967cddfSBarry Smith 58b967cddfSBarry Smith PetscFunctionBegin; 59b967cddfSBarry Smith if (!bio_err){ 60b967cddfSBarry Smith SSL_library_init(); 61b967cddfSBarry Smith SSL_load_error_strings(); 62b967cddfSBarry Smith bio_err = BIO_new_fp(stderr,BIO_NOCLOSE); 63b967cddfSBarry Smith } 64b967cddfSBarry Smith 65b967cddfSBarry Smith /* Set up a SIGPIPE handler */ 66b967cddfSBarry Smith signal(SIGPIPE,sigpipe_handle); 67b967cddfSBarry Smith 68b967cddfSBarry Smith meth = SSLv23_method(); 69b967cddfSBarry Smith ctx = SSL_CTX_new(meth); 70b967cddfSBarry Smith 71b967cddfSBarry Smith #if defined(PETSC_USE_CERTIFICATE) 72b967cddfSBarry Smith /* Locate keyfile */ 73b967cddfSBarry Smith ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr); 74b967cddfSBarry Smith ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 75b967cddfSBarry Smith if (!exists) { 76b967cddfSBarry Smith ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 77b967cddfSBarry Smith ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr); 78b967cddfSBarry Smith ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr); 79b967cddfSBarry Smith ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 80b967cddfSBarry Smith if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory"); 81b967cddfSBarry Smith } 82b967cddfSBarry Smith 83b967cddfSBarry Smith /* Load our keys and certificates*/ 84b967cddfSBarry Smith if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file"); 85b967cddfSBarry Smith 86b967cddfSBarry Smith SSL_CTX_set_default_passwd_cb(ctx,password_cb); 87b967cddfSBarry Smith if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file"); 88b967cddfSBarry Smith #endif 89b967cddfSBarry Smith 90b967cddfSBarry Smith *octx = ctx; 91b967cddfSBarry Smith PetscFunctionReturn(0); 92b967cddfSBarry Smith } 93b967cddfSBarry Smith 94b967cddfSBarry Smith #undef __FUNCT__ 95b967cddfSBarry Smith #define __FUNCT__ "PetscSSLDestroyContext" 96b967cddfSBarry Smith PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx) 97b967cddfSBarry Smith { 98b967cddfSBarry Smith PetscFunctionBegin; 99b967cddfSBarry Smith SSL_CTX_free(ctx); 100b967cddfSBarry Smith PetscFunctionReturn(0); 101b967cddfSBarry Smith } 102b967cddfSBarry Smith 103b967cddfSBarry Smith #undef __FUNCT__ 104b967cddfSBarry Smith #define __FUNCT__ "PetscHTTPSRequest" 105b967cddfSBarry Smith /* 106b967cddfSBarry Smith PetscHTTPSRequest - Send a request to an HTTPS server 107b967cddfSBarry Smith 108b967cddfSBarry Smith Input Parameters: 109b967cddfSBarry Smith + type - either "POST" or "GET" 110b967cddfSBarry Smith . url - complete URL of request including https:// 111b967cddfSBarry Smith . header - additional header information, may be NULL 112b967cddfSBarry Smith . ctype - data type of body, for example application/json 113b967cddfSBarry Smith . body - data to send to server 114b967cddfSBarry Smith . ssl - obtained with PetscHTTPSConnect() 115b967cddfSBarry Smith - buffsize - size of buffer 116b967cddfSBarry Smith 117b967cddfSBarry Smith Output Parameter: 118b967cddfSBarry Smith . buff - everything returned from server 119b967cddfSBarry Smith */ 120b967cddfSBarry Smith static PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize) 121b967cddfSBarry Smith { 122b967cddfSBarry Smith char *request=0; 123b967cddfSBarry Smith char contentlength[40],contenttype[80]; 124b967cddfSBarry Smith int r; 125b967cddfSBarry Smith size_t request_len,len,headlen,bodylen,contentlen,urllen,typelen,contenttypelen = 0; 126b967cddfSBarry Smith PetscErrorCode ierr; 127b967cddfSBarry Smith PetscBool flg; 128b967cddfSBarry Smith 129b967cddfSBarry Smith PetscFunctionBegin; 130b967cddfSBarry Smith ierr = PetscStrbeginswith(url,"https://",&flg);CHKERRQ(ierr); 131b967cddfSBarry Smith if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"URL must begin with https://"); 132b967cddfSBarry Smith if (header) { 133b967cddfSBarry Smith ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr); 134b967cddfSBarry Smith if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n"); 135b967cddfSBarry Smith } 136b967cddfSBarry Smith 137b967cddfSBarry Smith ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr); 138b967cddfSBarry Smith ierr = PetscStrlen(url,&urllen);CHKERRQ(ierr); 139b967cddfSBarry Smith if (ctype) { 140b967cddfSBarry Smith ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr); 141b967cddfSBarry Smith ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr); 142b967cddfSBarry Smith } 143b967cddfSBarry Smith ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr); 144b967cddfSBarry Smith ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr); 145b967cddfSBarry Smith ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr); 146b967cddfSBarry Smith ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr); 147b967cddfSBarry Smith 148b967cddfSBarry Smith /* Now construct our HTTP request */ 149b967cddfSBarry Smith request_len = typelen + 1 + urllen + 35 + headlen + contenttypelen + contentlen + bodylen + 1; 150*fe278a28SBarry Smith ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr); 151b967cddfSBarry Smith ierr = PetscStrcpy(request,type);CHKERRQ(ierr); 152b967cddfSBarry Smith ierr = PetscStrcat(request," ");CHKERRQ(ierr); 153b967cddfSBarry Smith ierr = PetscStrcat(request,url);CHKERRQ(ierr); 154b967cddfSBarry Smith ierr = PetscStrcat(request," HTTP/1.1\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr); 155b967cddfSBarry Smith ierr = PetscStrcat(request,header);CHKERRQ(ierr); 156b967cddfSBarry Smith if (ctype) { 157b967cddfSBarry Smith ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr); 158b967cddfSBarry Smith } 159b967cddfSBarry Smith ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr); 160b967cddfSBarry Smith ierr = PetscStrcat(request,body);CHKERRQ(ierr); 161b967cddfSBarry Smith ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 162b967cddfSBarry Smith ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr); 163b967cddfSBarry Smith 164b967cddfSBarry Smith r = SSL_write(ssl,request,request_len); 165b967cddfSBarry Smith switch (SSL_get_error(ssl,r)){ 166b967cddfSBarry Smith case SSL_ERROR_NONE: 167b967cddfSBarry Smith if (request_len != r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket"); 168b967cddfSBarry Smith break; 169b967cddfSBarry Smith default: 170b967cddfSBarry Smith SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem"); 171b967cddfSBarry Smith } 172b967cddfSBarry Smith 173b967cddfSBarry Smith /* Now read the server's response, assuming that it's terminated by a close */ 174b967cddfSBarry Smith r = SSL_read(ssl,buff,(int)buffsize); 175b967cddfSBarry Smith len = r; 176b967cddfSBarry Smith switch (SSL_get_error(ssl,r)){ 177b967cddfSBarry Smith case SSL_ERROR_NONE: 178b967cddfSBarry Smith break; 179b967cddfSBarry Smith case SSL_ERROR_ZERO_RETURN: 180b967cddfSBarry Smith SSL_shutdown(ssl); /* ignore shutdown error message */ 181b967cddfSBarry Smith break; 182b967cddfSBarry Smith case SSL_ERROR_SYSCALL: 183b967cddfSBarry Smith break; 184b967cddfSBarry Smith default: 185b967cddfSBarry Smith SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem"); 186b967cddfSBarry Smith } 187b967cddfSBarry Smith buff[len] = 0; /* null terminate string */ 188b967cddfSBarry Smith ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr); 189b967cddfSBarry Smith 190b967cddfSBarry Smith SSL_free(ssl); 191b967cddfSBarry Smith ierr = PetscFree(request);CHKERRQ(ierr); 192b967cddfSBarry Smith PetscFunctionReturn(0); 193b967cddfSBarry Smith } 194b967cddfSBarry Smith 195b967cddfSBarry Smith #undef __FUNCT__ 196b967cddfSBarry Smith #define __FUNCT__ "PetscHTTPSConnect" 197b967cddfSBarry Smith PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl) 198b967cddfSBarry Smith { 199b967cddfSBarry Smith BIO *sbio; 200b967cddfSBarry Smith PetscErrorCode ierr; 201b967cddfSBarry Smith 202b967cddfSBarry Smith PetscFunctionBegin; 203b967cddfSBarry Smith /* Connect the TCP socket*/ 204b967cddfSBarry Smith ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr); 205b967cddfSBarry Smith 206b967cddfSBarry Smith /* Connect the SSL socket */ 207b967cddfSBarry Smith *ssl = SSL_new(ctx); 208b967cddfSBarry Smith sbio = BIO_new_socket(*sock,BIO_NOCLOSE); 209b967cddfSBarry Smith SSL_set_bio(*ssl,sbio,sbio); 210b967cddfSBarry Smith if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error"); 211b967cddfSBarry Smith PetscFunctionReturn(0); 212b967cddfSBarry Smith } 213b967cddfSBarry Smith 214b967cddfSBarry Smith /* 215b967cddfSBarry Smith This file is not included in the respository since it contains authorization secrets 216b967cddfSBarry Smith */ 217b967cddfSBarry Smith #include <../src/sys/webclient/authorization.h> 218b967cddfSBarry Smith 219b967cddfSBarry Smith #undef __FUNCT__ 220b967cddfSBarry Smith #define __FUNCT__ "PetscGoogleDriveRefresh" 221*fe278a28SBarry Smith /*@C 222b967cddfSBarry Smith PetscGoogleDriveRefresh - Get a new authorization token for accessing Google drive from PETSc from a refresh token 223b967cddfSBarry Smith 224*fe278a28SBarry Smith Not collective, only the first process in the MPI_Comm does anything 225b967cddfSBarry Smith 226*fe278a28SBarry Smith Input Parameters: 227*fe278a28SBarry Smith + comm - MPI communicator 228*fe278a28SBarry Smith . refresh token - obtained with PetscGoogleDriveAuthorize(), if NULL PETSc will first look for one in the options data 229*fe278a28SBarry Smith if not found it will call PetscGoogleDriveAuthorize() 230*fe278a28SBarry Smith - tokensize - size of the output string access_token 231*fe278a28SBarry Smith 232*fe278a28SBarry Smith Output Parameter: 233*fe278a28SBarry Smith . access_token - token that can be passed to PetscGoogleDriveUpload() 234*fe278a28SBarry Smith 235*fe278a28SBarry Smith .seealso: PetscURLShorten(), PetscGoogleDriveAuthorize(), PetscGoogleDriveUpload() 236*fe278a28SBarry Smith 237*fe278a28SBarry Smith @*/ 238b967cddfSBarry Smith PetscErrorCode PetscGoogleDriveRefresh(MPI_Comm comm,const char refresh_token[],char access_token[],size_t tokensize) 239b967cddfSBarry Smith { 240b967cddfSBarry Smith SSL_CTX *ctx; 241b967cddfSBarry Smith SSL *ssl; 242b967cddfSBarry Smith int sock; 243b967cddfSBarry Smith PetscErrorCode ierr; 244b967cddfSBarry Smith char buff[8*1024],body[1024],*access,*ctmp; 245b967cddfSBarry Smith PetscMPIInt rank; 246*fe278a28SBarry Smith char *refreshtoken = (char*)refresh_token; 247b967cddfSBarry Smith 248b967cddfSBarry Smith PetscFunctionBegin; 249b967cddfSBarry Smith ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 250b967cddfSBarry Smith if (!rank) { 251*fe278a28SBarry Smith if (!refresh_token) { 252*fe278a28SBarry Smith PetscBool set; 253*fe278a28SBarry Smith ierr = PetscMalloc1(512,&refreshtoken);CHKERRQ(ierr); 254*fe278a28SBarry Smith ierr = PetscOptionsGetString(NULL,"-refresh_token",refreshtoken,512,&set);CHKERRQ(ierr); 255*fe278a28SBarry Smith if (!set) { 256*fe278a28SBarry Smith ierr = PetscGoogleDriveAuthorize(comm,access_token,refreshtoken,512*sizeof(char));CHKERRQ(ierr); 257*fe278a28SBarry Smith ierr = PetscFree(refreshtoken);CHKERRQ(ierr); 258*fe278a28SBarry Smith PetscFunctionReturn(0); 259*fe278a28SBarry Smith } 260*fe278a28SBarry Smith } 261b967cddfSBarry Smith ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 262b967cddfSBarry Smith ierr = PetscHTTPSConnect("accounts.google.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 263b967cddfSBarry Smith ierr = PetscStrcpy(body,"&client_id=");CHKERRQ(ierr); 264b967cddfSBarry Smith ierr = PetscStrcat(body,PETSC_CLIENT_ID);CHKERRQ(ierr); 265b967cddfSBarry Smith ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr); 266b967cddfSBarry Smith ierr = PetscStrcat(body,PETSC_CLIENT_SECRET);CHKERRQ(ierr); 267b967cddfSBarry Smith ierr = PetscStrcat(body,"&refresh_token=");CHKERRQ(ierr); 268*fe278a28SBarry Smith ierr = PetscStrcat(body,refreshtoken);CHKERRQ(ierr); 269*fe278a28SBarry Smith if (!refresh_token) {ierr = PetscFree(refreshtoken);CHKERRQ(ierr);} 270b967cddfSBarry Smith ierr = PetscStrcat(body,"&grant_type=refresh_token");CHKERRQ(ierr); 271b967cddfSBarry Smith 272b967cddfSBarry Smith ierr = PetscHTTPSRequest("POST","https://accounts.google.com/o/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 273b967cddfSBarry Smith ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 274b967cddfSBarry Smith close(sock); 275b967cddfSBarry Smith 276b967cddfSBarry Smith ierr = PetscStrstr(buff,"\"access_token\" : \"",&access);CHKERRQ(ierr); 277b967cddfSBarry Smith if (!access) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not receive access token from Google"); 278b967cddfSBarry Smith access += 18; 279b967cddfSBarry Smith ierr = PetscStrchr(access,'\"',&ctmp);CHKERRQ(ierr); 280b967cddfSBarry Smith if (!ctmp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Access token from Google is misformed"); 281b967cddfSBarry Smith *ctmp = 0; 282b967cddfSBarry Smith ierr = PetscStrncpy(access_token,access,tokensize);CHKERRQ(ierr); 283b967cddfSBarry Smith *ctmp = '\"'; 284b967cddfSBarry Smith } 285b967cddfSBarry Smith PetscFunctionReturn(0); 286b967cddfSBarry Smith } 287b967cddfSBarry Smith 288b967cddfSBarry Smith #include <sys/stat.h> 289b967cddfSBarry Smith 290b967cddfSBarry Smith #undef __FUNCT__ 291b967cddfSBarry Smith #define __FUNCT__ "PetscGoogleDriveUpload" 292b967cddfSBarry Smith /*@C 293*fe278a28SBarry Smith PetscGoogleDriveUpload - Loads a file to the Google Drive 294b967cddfSBarry Smith 295b967cddfSBarry Smith Not collective, only the first process in the MPI_Comm uploads the file 296b967cddfSBarry Smith 297b967cddfSBarry Smith Input Parameters: 298b967cddfSBarry Smith + comm - MPI communicator 299*fe278a28SBarry Smith . access_token - obtained with PetscGoogleDriveRefresh(), pass NULL to have PETSc generate one 300b967cddfSBarry Smith - filename - file to upload; if you upload multiple times it will have different names each time on Google Drive 301b967cddfSBarry Smith 302*fe278a28SBarry Smith Options Database: 303*fe278a28SBarry Smith . -refresh_token XXX 304*fe278a28SBarry Smith 305*fe278a28SBarry Smith Usage Patterns: 306*fe278a28SBarry Smith With PETSc option -refresh_token XXX given 307*fe278a28SBarry Smith PetscGoogleDriveUpload(comm,NULL,filename); will upload file with no user interaction 308*fe278a28SBarry Smith 309*fe278a28SBarry Smith Without PETSc option -refresh_token XXX given 310*fe278a28SBarry Smith PetscGoogleDriveUpload(comm,NULL,filename); for first use will prompt user to authorize access to Google Drive with their processor 311*fe278a28SBarry Smith 312*fe278a28SBarry Smith With PETSc option -refresh_token XXX given 313*fe278a28SBarry Smith PetscGoogleDriveRefresh(comm,NULL,access_token,sizeof(access_token)); 314*fe278a28SBarry Smith PetscGoogleDriveUpload(comm,access_token,filename); 315*fe278a28SBarry Smith 316*fe278a28SBarry Smith With refresh token entered in some way by the user 317*fe278a28SBarry Smith PetscGoogleDriveRefresh(comm,refresh_token,access_token,sizeof(access_token)); 318*fe278a28SBarry Smith PetscGoogleDriveUpload(comm,access_token,filename); 319*fe278a28SBarry Smith 320*fe278a28SBarry Smith PetscGoogleDriveAuthorize(comm,access_token,refresh_token,sizeof(access_token)); 321*fe278a28SBarry Smith PetscGoogleDriveUpload(comm,access_token,filename); 322*fe278a28SBarry Smith 323*fe278a28SBarry Smith .seealso: PetscURLShorten(), PetscGoogleDriveAuthorize(), PetscGoogleDriveRefresh() 324*fe278a28SBarry Smith 325b967cddfSBarry Smith @*/ 326b967cddfSBarry Smith PetscErrorCode PetscGoogleDriveUpload(MPI_Comm comm,const char access_token[],const char filename[]) 327b967cddfSBarry Smith { 328b967cddfSBarry Smith SSL_CTX *ctx; 329b967cddfSBarry Smith SSL *ssl; 330b967cddfSBarry Smith int sock; 331b967cddfSBarry Smith PetscErrorCode ierr; 332b967cddfSBarry Smith char head[1024],buff[8*1024],*body,*title; 333b967cddfSBarry Smith PetscMPIInt rank; 334b967cddfSBarry Smith struct stat sb; 335b967cddfSBarry Smith size_t len,blen,rd; 336b967cddfSBarry Smith FILE *fd; 337b967cddfSBarry Smith 338b967cddfSBarry Smith PetscFunctionBegin; 339b967cddfSBarry Smith ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 340b967cddfSBarry Smith if (!rank) { 341b967cddfSBarry Smith ierr = PetscStrcpy(head,"Authorization: Bearer ");CHKERRQ(ierr); 342b967cddfSBarry Smith ierr = PetscStrcat(head,access_token);CHKERRQ(ierr); 343b967cddfSBarry Smith ierr = PetscStrcat(head,"\r\n");CHKERRQ(ierr); 344b967cddfSBarry Smith ierr = PetscStrcat(head,"uploadType: multipart\r\n");CHKERRQ(ierr); 345b967cddfSBarry Smith 346b967cddfSBarry Smith ierr = stat(filename,&sb); 347b967cddfSBarry Smith if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to stat file: %s",filename); 348b967cddfSBarry Smith len = 1024 + sb.st_size; 349*fe278a28SBarry Smith ierr = PetscMalloc1(len,&body);CHKERRQ(ierr); 350b967cddfSBarry Smith ierr = PetscStrcpy(body,"--foo_bar_baz\r\n" 351b967cddfSBarry Smith "Content-Type: application/json\r\n\r\n" 352b967cddfSBarry Smith "{" 353b967cddfSBarry Smith "\"title\": \""); 354b967cddfSBarry Smith ierr = PetscStrcat(body,filename); 355b967cddfSBarry Smith ierr = PetscStrcat(body,"\"," 356b967cddfSBarry Smith "\"mimeType\": \"text.html\"," 357b967cddfSBarry Smith "\"description\": \" a file\"" 358b967cddfSBarry Smith "}\r\n\r\n" 359b967cddfSBarry Smith "--foo_bar_baz\r\n" 360b967cddfSBarry Smith "Content-Type: text/html\r\n\r\n"); 361b967cddfSBarry Smith ierr = PetscStrlen(body,&blen);CHKERRQ(ierr); 362b967cddfSBarry Smith fd = fopen (filename, "r"); 363b967cddfSBarry Smith if (!fd) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open file: %s",filename); 364b967cddfSBarry Smith rd = fread (body+blen, sizeof (unsigned char), sb.st_size, fd); 365b967cddfSBarry Smith if (rd != sb.st_size) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to read entire file: %s %d %d",filename,(int)rd,sb.st_size); 366b967cddfSBarry Smith fclose(fd); 367b967cddfSBarry Smith body[blen + rd] = 0; 368b967cddfSBarry Smith ierr = PetscStrcat(body,"\r\n\r\n" 369b967cddfSBarry Smith "--foo_bar_baz\r\n"); 370b967cddfSBarry Smith ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 371b967cddfSBarry Smith ierr = PetscHTTPSConnect("www.googleapis.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 372b967cddfSBarry Smith ierr = PetscHTTPSRequest("POST","https://www.googleapis.com/upload/drive/v2/files/",head,"multipart/related; boundary=\"foo_bar_baz\"",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 373*fe278a28SBarry Smith ierr = PetscFree(body);CHKERRQ(ierr); 374b967cddfSBarry Smith ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 375b967cddfSBarry Smith close(sock); 376b967cddfSBarry Smith ierr = PetscStrstr(buff,"\"title\"",&title);CHKERRQ(ierr); 377b967cddfSBarry Smith if (!title) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Upload of file %s failed",filename); 378b967cddfSBarry Smith } 379b967cddfSBarry Smith PetscFunctionReturn(0); 380b967cddfSBarry Smith } 381b967cddfSBarry Smith 382b967cddfSBarry Smith 383b967cddfSBarry Smith #undef __FUNCT__ 384b967cddfSBarry Smith #define __FUNCT__ "PetscGoogleDriveAuthorize" 385*fe278a28SBarry Smith /*@C 386b967cddfSBarry Smith PetscGoogleDriveAuthorize - Get authorization and refresh token for accessing Google drive from PETSc 387b967cddfSBarry Smith 388*fe278a28SBarry Smith Not collective, only the first process in MPI_Comm does anything 389b967cddfSBarry Smith 390*fe278a28SBarry Smith Input Parameters: 391*fe278a28SBarry Smith + comm - the MPI communicator 392*fe278a28SBarry Smith - tokensize - size of the token arrays 393*fe278a28SBarry Smith 394*fe278a28SBarry Smith Output Parameters: 395*fe278a28SBarry Smith + access_token - can be used with PetscGoogleDriveUpload() for this one session 396*fe278a28SBarry Smith - refresh_token - can be used for ever to obtain new access_tokens with PetscGoogleDriveRefresh(), guard this like a password 397*fe278a28SBarry Smith it gives access to your Google Drive 398*fe278a28SBarry Smith 399*fe278a28SBarry Smith Notes: This call requires stdout and stdin access from process 0 on the MPI communicator 400*fe278a28SBarry Smith 401*fe278a28SBarry Smith You can run src/sys/webclient/examples/tutorials/obtainrefreshtoken to get a refresh token and then in the future pass it to 402*fe278a28SBarry Smith PETSc programs with -refresh_token XXX 403*fe278a28SBarry Smith 404*fe278a28SBarry Smith .seealso: PetscGoogleDriveRefresh(), PetscGoogleDriveUpload(), PetscURLShorten() 405*fe278a28SBarry Smith 406*fe278a28SBarry Smith @*/ 407b967cddfSBarry Smith PetscErrorCode PetscGoogleDriveAuthorize(MPI_Comm comm,char access_token[],char refresh_token[],size_t tokensize) 408b967cddfSBarry Smith { 409b967cddfSBarry Smith SSL_CTX *ctx; 410b967cddfSBarry Smith SSL *ssl; 411b967cddfSBarry Smith int sock; 412b967cddfSBarry Smith PetscErrorCode ierr; 413b967cddfSBarry Smith char buff[8*1024],*ptr,body[1024],*access,*refresh,*ctmp; 414b967cddfSBarry Smith PetscMPIInt rank; 415b967cddfSBarry Smith size_t len; 416b967cddfSBarry Smith 417b967cddfSBarry Smith PetscFunctionBegin; 418b967cddfSBarry Smith ierr = PetscPrintf(comm,"Cut and paste the following into your browser:\n" 419b967cddfSBarry Smith "https://accounts.google.com/o/oauth2/auth?" 420b967cddfSBarry Smith "scope=https%%3A%%2F%%2Fwww.googleapis.com%%2Fauth%%2Fdrive.file&" 421b967cddfSBarry Smith "redirect_uri=urn:ietf:wg:oauth:2.0:oob&" 422b967cddfSBarry Smith "response_type=code&" 423b967cddfSBarry Smith "client_id=" 424b967cddfSBarry Smith PETSC_CLIENT_ID 425b967cddfSBarry Smith "\n\n");CHKERRQ(ierr); 426b967cddfSBarry Smith ierr = PetscPrintf(comm,"Paste the result here:");CHKERRQ(ierr); 427b967cddfSBarry Smith ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 428b967cddfSBarry Smith if (!rank) { 429b967cddfSBarry Smith ptr = fgets(buff, 1024, stdin); 430b967cddfSBarry Smith if (!ptr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno); 431b967cddfSBarry Smith ierr = PetscStrlen(buff,&len);CHKERRQ(ierr); 432b967cddfSBarry Smith buff[len-1] = 0; /* remove carriage return at end of line */ 433b967cddfSBarry Smith 434b967cddfSBarry Smith ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 435b967cddfSBarry Smith ierr = PetscHTTPSConnect("accounts.google.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 436b967cddfSBarry Smith ierr = PetscStrcpy(body,"code=");CHKERRQ(ierr); 437b967cddfSBarry Smith ierr = PetscStrcat(body,buff);CHKERRQ(ierr); 438b967cddfSBarry Smith ierr = PetscStrcat(body,"&client_id=");CHKERRQ(ierr); 439b967cddfSBarry Smith ierr = PetscStrcat(body,PETSC_CLIENT_ID);CHKERRQ(ierr); 440b967cddfSBarry Smith ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr); 441b967cddfSBarry Smith ierr = PetscStrcat(body,PETSC_CLIENT_SECRET);CHKERRQ(ierr); 442b967cddfSBarry Smith ierr = PetscStrcat(body,"&redirect_uri=urn:ietf:wg:oauth:2.0:oob&");CHKERRQ(ierr); 443b967cddfSBarry Smith ierr = PetscStrcat(body,"grant_type=authorization_code");CHKERRQ(ierr); 444b967cddfSBarry Smith 445b967cddfSBarry Smith ierr = PetscHTTPSRequest("POST","https://accounts.google.com/o/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 446b967cddfSBarry Smith ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 447b967cddfSBarry Smith close(sock); 448b967cddfSBarry Smith 449b967cddfSBarry Smith ierr = PetscStrstr(buff,"\"access_token\" : \"",&access);CHKERRQ(ierr); 450b967cddfSBarry Smith if (!access) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not receive access token from Google"); 451b967cddfSBarry Smith access += 18; 452b967cddfSBarry Smith ierr = PetscStrchr(access,'\"',&ctmp);CHKERRQ(ierr); 453b967cddfSBarry Smith if (!ctmp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Access token from Google is misformed"); 454b967cddfSBarry Smith *ctmp = 0; 455b967cddfSBarry Smith ierr = PetscStrncpy(access_token,access,tokensize);CHKERRQ(ierr); 456b967cddfSBarry Smith *ctmp = '\"'; 457b967cddfSBarry Smith 458b967cddfSBarry Smith ierr = PetscStrstr(buff,"\"refresh_token\" : \"",&refresh);CHKERRQ(ierr); 459b967cddfSBarry Smith if (!refresh) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not receive refresh token from Google"); 460b967cddfSBarry Smith refresh += 19; 461b967cddfSBarry Smith ierr = PetscStrchr(refresh,'\"',&ctmp);CHKERRQ(ierr); 462b967cddfSBarry Smith if (!ctmp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Refresh token from Google is misformed"); 463b967cddfSBarry Smith *ctmp = 0; 464b967cddfSBarry Smith ierr = PetscStrncpy(refresh_token,refresh,tokensize);CHKERRQ(ierr); 465b967cddfSBarry Smith } 466b967cddfSBarry Smith PetscFunctionReturn(0); 467b967cddfSBarry Smith } 468b967cddfSBarry Smith 469b967cddfSBarry Smith 470b967cddfSBarry Smith #undef __FUNCT__ 471b967cddfSBarry Smith #define __FUNCT__ "PetscURLShorten" 472b967cddfSBarry Smith /*@C 473b967cddfSBarry Smith PetscURLShorten - Uses Google's service to get a short url for a long url 474b967cddfSBarry Smith 475b967cddfSBarry Smith Input Parameters: 476b967cddfSBarry Smith + url - long URL you want shortened 477b967cddfSBarry Smith - lenshorturl - length of buffer to contain short URL 478b967cddfSBarry Smith 479b967cddfSBarry Smith Output Parameter: 480b967cddfSBarry Smith . shorturl - the shortened URL 481b967cddfSBarry Smith 482*fe278a28SBarry Smith .seealso: PetscGoogleDriveRefresh(), PetscGoogleDriveUpload(), PetscGoogleDriveAuthorize() 483b967cddfSBarry Smith @*/ 484b967cddfSBarry Smith PetscErrorCode PetscURLShorten(const char url[],char shorturl[],size_t lenshorturl) 485b967cddfSBarry Smith { 486b967cddfSBarry Smith SSL_CTX *ctx; 487b967cddfSBarry Smith SSL *ssl; 488b967cddfSBarry Smith int sock; 489b967cddfSBarry Smith PetscErrorCode ierr; 490b967cddfSBarry Smith char buff[1024],body[512],*sub1,*sub2; 491b967cddfSBarry Smith 492b967cddfSBarry Smith PetscFunctionBegin; 493b967cddfSBarry Smith ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 494b967cddfSBarry Smith ierr = PetscHTTPSConnect("www.googleapis.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 495b967cddfSBarry Smith ierr = PetscSNPrintf(body,512,"{\"longUrl\": \"%s\"}",url);CHKERRQ(ierr); 496b967cddfSBarry Smith ierr = PetscHTTPSRequest("POST","https://www.googleapis.com/urlshortener/v1/url",NULL,"application/json",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 497b967cddfSBarry Smith ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 498b967cddfSBarry Smith close(sock); 499b967cddfSBarry Smith ierr = PetscStrstr(buff,"\"id\": \"",&sub1);CHKERRQ(ierr); 500b967cddfSBarry Smith if (sub1) { 501b967cddfSBarry Smith sub1 += 7; 502b967cddfSBarry Smith ierr = PetscStrstr(sub1,"\"",&sub2);CHKERRQ(ierr); 503b967cddfSBarry Smith if (!sub2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Google did not shorten URL"); 504b967cddfSBarry Smith sub2[0] = 0; 505b967cddfSBarry Smith ierr = PetscStrncpy(shorturl,sub1,lenshorturl);CHKERRQ(ierr); 506b967cddfSBarry Smith } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Google did not shorten URL"); 507b967cddfSBarry Smith PetscFunctionReturn(0); 508b967cddfSBarry Smith } 509b967cddfSBarry Smith 510