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