1 2 #include <petscwebclient.h> 3 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 4 #pragma gcc diagnostic ignored "-Wdeprecated-declarations" 5 6 /* 7 These variables identify the code as a PETSc application to Box. 8 9 See - http://stackoverflow.com/questions/4616553/using-oauth-in-free-open-source-software 10 Users can get their own application IDs - goto https://developers.box.com 11 12 */ 13 #define PETSC_BOX_CLIENT_ID "sse42nygt4zqgrdwi0luv79q1u1f0xza" 14 #define PETSC_BOX_CLIENT_ST "A0Dy4KgOYLB2JIYZqpbze4EzjeIiX5k4" 15 16 #if defined(PETSC_HAVE_SAWS) 17 #include <mongoose.h> 18 19 static volatile char *result = NULL; 20 21 static int PetscBoxWebServer_Private(struct mg_connection *conn) 22 { 23 const struct mg_request_info *request_info = mg_get_request_info(conn); 24 result = (char*) request_info->query_string; 25 return 1; /* Mongoose will now not handle the request */ 26 } 27 28 /* 29 Box can only return an authorization code to a Webserver, hence we need to start one up and wait for 30 the authorization code to arrive from Box 31 */ 32 static PetscErrorCode PetscBoxStartWebServer_Private(void) 33 { 34 PetscErrorCode ierr; 35 int optionsLen = 5; 36 const char *options[optionsLen]; 37 struct mg_callbacks callbacks; 38 struct mg_context *ctx; 39 char keyfile[PETSC_MAX_PATH_LEN]; 40 PetscBool exists; 41 42 PetscFunctionBegin; 43 options[0] = "listening_ports"; 44 options[1] = "8081s"; 45 46 ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr); 47 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 48 if (!exists) { 49 ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 50 ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr); 51 ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr); 52 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 53 if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory"); 54 } 55 56 options[2] = "ssl_certificate"; 57 options[3] = keyfile; 58 options[4] = NULL; 59 60 /* Prepare callbacks structure. We have only one callback, the rest are NULL. */ 61 ierr = PetscMemzero(&callbacks, sizeof(callbacks));CHKERRQ(ierr); 62 callbacks.begin_request = PetscBoxWebServer_Private; 63 ctx = mg_start(&callbacks, NULL, options); 64 if (!ctx) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to start up webserver"); 65 while (!result) {}; 66 PetscFunctionReturn(0); 67 } 68 69 #if defined(PETSC_HAVE_UNISTD_H) 70 #include <unistd.h> 71 #endif 72 73 #undef __FUNCT__ 74 #define __FUNCT__ "PetscBoxAuthorize" 75 /*@C 76 PetscBoxAuthorize - Get authorization and refresh token for accessing Box drive from PETSc 77 78 Not collective, only the first process in MPI_Comm does anything 79 80 Input Parameters: 81 + comm - the MPI communicator 82 - tokensize - size of the token arrays 83 84 Output Parameters: 85 + access_token - can be used with PetscBoxUpload() for this one session 86 - refresh_token - can be used for ever to obtain new access_tokens with PetscBoxRefresh(), guard this like a password 87 it gives access to your Box Drive 88 89 Notes: This call requires stdout and stdin access from process 0 on the MPI communicator 90 91 You can run src/sys/webclient/examples/tutorials/boxobtainrefreshtoken to get a refresh token and then in the future pass it to 92 PETSc programs with -box_refresh_token XXX 93 94 This requires PETSc be installed using --with-saws or --download-saws 95 96 Requires the user have created a self-signed ssl certificate with 97 98 $ saws/CA.pl -newcert (using the passphrase of password) 99 $ cat newkey.pem newcert.pem > sslclient.pem 100 101 and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of 102 silly but it was all I could figure out. 103 104 Level: intermediate 105 106 .seealso: PetscBoxRefresh(), PetscBoxUpload(), PetscURLShorten() 107 108 @*/ 109 PetscErrorCode PetscBoxAuthorize(MPI_Comm comm,char access_token[],char refresh_token[],size_t tokensize) 110 { 111 SSL_CTX *ctx; 112 SSL *ssl; 113 int sock; 114 PetscErrorCode ierr; 115 char buff[8*1024],body[1024]; 116 PetscMPIInt rank; 117 PetscBool flg,found; 118 119 PetscFunctionBegin; 120 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 121 if (!rank) { 122 if (!isatty(fileno(PETSC_STDOUT))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Requires users input/output"); 123 ierr = PetscPrintf(comm,"Cut and paste the following into your browser:\n\n" 124 "https://www.box.com/api/oauth2/authorize?" 125 "response_type=code&" 126 "client_id=" 127 PETSC_BOX_CLIENT_ID 128 "&state=PETScState" 129 "\n\n");CHKERRQ(ierr); 130 ierr = PetscBoxStartWebServer_Private();CHKERRQ(ierr); 131 ierr = PetscStrbeginswith((const char*)result,"state=PETScState&code=",&flg);CHKERRQ(ierr); 132 if (!flg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not get expected string from Box got %s",result); 133 ierr = PetscStrncpy(buff,(const char*)result+22,sizeof(buff));CHKERRQ(ierr); 134 135 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 136 ierr = PetscHTTPSConnect("www.box.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 137 ierr = PetscStrcpy(body,"code=");CHKERRQ(ierr); 138 ierr = PetscStrcat(body,buff);CHKERRQ(ierr); 139 ierr = PetscStrcat(body,"&client_id=");CHKERRQ(ierr); 140 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ID);CHKERRQ(ierr); 141 ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr); 142 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ST);CHKERRQ(ierr); 143 ierr = PetscStrcat(body,"&grant_type=authorization_code");CHKERRQ(ierr); 144 145 ierr = PetscHTTPSRequest("POST","www.box.com/api/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 146 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 147 close(sock); 148 149 ierr = PetscPullJSONValue(buff,"access_token",access_token,tokensize,&found);CHKERRQ(ierr); 150 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return access token"); 151 ierr = PetscPullJSONValue(buff,"refresh_token",refresh_token,tokensize,&found);CHKERRQ(ierr); 152 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return refresh token"); 153 154 ierr = PetscPrintf(comm,"Here is your Box refresh token, save it in a save place, in the future you can run PETSc\n");CHKERRQ(ierr); 155 ierr = PetscPrintf(comm,"programs with the option -box_refresh_token %s\n",refresh_token);CHKERRQ(ierr); 156 ierr = PetscPrintf(comm,"to access Box Drive automatically\n");CHKERRQ(ierr); 157 } 158 PetscFunctionReturn(0); 159 } 160 #endif 161 162 #undef __FUNCT__ 163 #define __FUNCT__ "PetscBoxRefresh" 164 /*@C 165 PetscBoxRefresh - Get a new authorization token for accessing Box drive from PETSc from a refresh token 166 167 Not collective, only the first process in the MPI_Comm does anything 168 169 Input Parameters: 170 + comm - MPI communicator 171 . refresh token - obtained with PetscBoxAuthorize(), if NULL PETSc will first look for one in the options data 172 if not found it will call PetscBoxAuthorize() 173 - tokensize - size of the output string access_token 174 175 Output Parameter: 176 + access_token - token that can be passed to PetscBoxUpload() 177 - new_refresh_token - the old refresh token is no longer valid, not this is different than Google where the same refresh_token is used forever 178 179 Level: intermediate 180 181 .seealso: PetscURLShorten(), PetscBoxAuthorize(), PetscBoxUpload() 182 183 @*/ 184 PetscErrorCode PetscBoxRefresh(MPI_Comm comm,const char refresh_token[],char access_token[],char new_refresh_token[],size_t tokensize) 185 { 186 SSL_CTX *ctx; 187 SSL *ssl; 188 int sock; 189 PetscErrorCode ierr; 190 char buff[8*1024],body[1024]; 191 PetscMPIInt rank; 192 char *refreshtoken = (char*)refresh_token; 193 PetscBool found; 194 195 PetscFunctionBegin; 196 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 197 if (!rank) { 198 if (!refresh_token) { 199 PetscBool set; 200 ierr = PetscMalloc1(512,&refreshtoken);CHKERRQ(ierr); 201 ierr = PetscOptionsGetString(NULL,"-box_refresh_token",refreshtoken,512,&set);CHKERRQ(ierr); 202 #if defined(PETSC_HAVE_SAWS) 203 if (!set) { 204 ierr = PetscBoxAuthorize(comm,access_token,new_refresh_token,512*sizeof(char));CHKERRQ(ierr); 205 ierr = PetscFree(refreshtoken);CHKERRQ(ierr); 206 PetscFunctionReturn(0); 207 } 208 #else 209 if (!set) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Must provide refresh token with -box_refresh_token XXX"); 210 #endif 211 } 212 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 213 ierr = PetscHTTPSConnect("www.box.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 214 ierr = PetscStrcpy(body,"client_id=");CHKERRQ(ierr); 215 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ID);CHKERRQ(ierr); 216 ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr); 217 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ST);CHKERRQ(ierr); 218 ierr = PetscStrcat(body,"&refresh_token=");CHKERRQ(ierr); 219 ierr = PetscStrcat(body,refreshtoken);CHKERRQ(ierr); 220 if (!refresh_token) {ierr = PetscFree(refreshtoken);CHKERRQ(ierr);} 221 ierr = PetscStrcat(body,"&grant_type=refresh_token");CHKERRQ(ierr); 222 223 ierr = PetscHTTPSRequest("POST","www.box.com/api/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 224 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 225 close(sock); 226 227 ierr = PetscPullJSONValue(buff,"access_token",access_token,tokensize,&found);CHKERRQ(ierr); 228 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return access token"); 229 ierr = PetscPullJSONValue(buff,"refresh_token",new_refresh_token,tokensize,&found);CHKERRQ(ierr); 230 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return refresh token"); 231 232 ierr = PetscPrintf(comm,"Here is your new Box refresh token, save it in a save place, in the future you can run PETSc\n");CHKERRQ(ierr); 233 ierr = PetscPrintf(comm,"programs with the option -box_refresh_token %s\n",new_refresh_token);CHKERRQ(ierr); 234 ierr = PetscPrintf(comm,"to access Box Drive automatically\n");CHKERRQ(ierr); 235 } 236 PetscFunctionReturn(0); 237 } 238 239 #include <sys/stat.h> 240 241 #undef __FUNCT__ 242 #define __FUNCT__ "PetscBoxUpload" 243 /*@C 244 PetscBoxUpload - Loads a file to the Box Drive 245 246 This routine has not yet been written; it is just copied from Google Drive 247 248 Not collective, only the first process in the MPI_Comm uploads the file 249 250 Input Parameters: 251 + comm - MPI communicator 252 . access_token - obtained with PetscBoxRefresh(), pass NULL to have PETSc generate one 253 - filename - file to upload; if you upload multiple times it will have different names each time on Box Drive 254 255 Options Database: 256 . -box_refresh_token XXX 257 258 Usage Patterns: 259 With PETSc option -box_refresh_token XXX given 260 PetscBoxUpload(comm,NULL,filename); will upload file with no user interaction 261 262 Without PETSc option -box_refresh_token XXX given 263 PetscBoxUpload(comm,NULL,filename); for first use will prompt user to authorize access to Box Drive with their processor 264 265 With PETSc option -box_refresh_token XXX given 266 PetscBoxRefresh(comm,NULL,access_token,sizeof(access_token)); 267 PetscBoxUpload(comm,access_token,filename); 268 269 With refresh token entered in some way by the user 270 PetscBoxRefresh(comm,refresh_token,access_token,sizeof(access_token)); 271 PetscBoxUpload(comm,access_token,filename); 272 273 PetscBoxAuthorize(comm,access_token,refresh_token,sizeof(access_token)); 274 PetscBoxUpload(comm,access_token,filename); 275 276 Level: intermediate 277 278 .seealso: PetscURLShorten(), PetscBoxAuthorize(), PetscBoxRefresh() 279 280 @*/ 281 PetscErrorCode PetscBoxUpload(MPI_Comm comm,const char access_token[],const char filename[]) 282 { 283 SSL_CTX *ctx; 284 SSL *ssl; 285 int sock; 286 PetscErrorCode ierr; 287 char head[1024],buff[8*1024],*body,*title; 288 PetscMPIInt rank; 289 struct stat sb; 290 size_t len,blen,rd; 291 FILE *fd; 292 293 PetscFunctionBegin; 294 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 295 if (!rank) { 296 ierr = PetscStrcpy(head,"Authorization: Bearer ");CHKERRQ(ierr); 297 ierr = PetscStrcat(head,access_token);CHKERRQ(ierr); 298 ierr = PetscStrcat(head,"\r\n");CHKERRQ(ierr); 299 ierr = PetscStrcat(head,"uploadType: multipart\r\n");CHKERRQ(ierr); 300 301 ierr = stat(filename,&sb); 302 if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to stat file: %s",filename); 303 len = 1024 + sb.st_size; 304 ierr = PetscMalloc1(len,&body);CHKERRQ(ierr); 305 ierr = PetscStrcpy(body,"--foo_bar_baz\r\n" 306 "Content-Type: application/json\r\n\r\n" 307 "{");CHKERRQ(ierr); 308 ierr = PetscPushJSONValue(body,"title",filename,len);CHKERRQ(ierr); 309 ierr = PetscStrcat(body,",");CHKERRQ(ierr); 310 ierr = PetscPushJSONValue(body,"mimeType","text.html",len);CHKERRQ(ierr); 311 ierr = PetscStrcat(body,",");CHKERRQ(ierr); 312 ierr = PetscPushJSONValue(body,"description","a file",len);CHKERRQ(ierr); 313 ierr = PetscStrcat(body, "}\r\n\r\n" 314 "--foo_bar_baz\r\n" 315 "Content-Type: text/html\r\n\r\n");CHKERRQ(ierr); 316 ierr = PetscStrlen(body,&blen);CHKERRQ(ierr); 317 fd = fopen (filename, "r"); 318 if (!fd) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open file: %s",filename); 319 rd = fread (body+blen, sizeof (unsigned char), sb.st_size, fd); 320 if (rd != (size_t)sb.st_size) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to read entire file: %s %d %d",filename,(int)rd,(int)sb.st_size); 321 fclose(fd); 322 body[blen + rd] = 0; 323 ierr = PetscStrcat(body,"\r\n\r\n" 324 "--foo_bar_baz\r\n");CHKERRQ(ierr); 325 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 326 ierr = PetscHTTPSConnect("www.boxapis.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 327 ierr = PetscHTTPSRequest("POST","www.boxapis.com/upload/drive/v2/files/",head,"multipart/related; boundary=\"foo_bar_baz\"",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 328 ierr = PetscFree(body);CHKERRQ(ierr); 329 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 330 close(sock); 331 ierr = PetscStrstr(buff,"\"title\"",&title);CHKERRQ(ierr); 332 if (!title) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Upload of file %s failed",filename); 333 } 334 PetscFunctionReturn(0); 335 } 336 337 338