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 .seealso: PetscBoxRefresh(), PetscBoxUpload(), PetscURLShorten() 105 106 @*/ 107 PetscErrorCode PetscBoxAuthorize(MPI_Comm comm,char access_token[],char refresh_token[],size_t tokensize) 108 { 109 SSL_CTX *ctx; 110 SSL *ssl; 111 int sock; 112 PetscErrorCode ierr; 113 char buff[8*1024],body[1024]; 114 PetscMPIInt rank; 115 PetscBool flg,found; 116 117 PetscFunctionBegin; 118 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 119 if (!rank) { 120 if (!isatty(fileno(PETSC_STDOUT))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Requires users input/output"); 121 ierr = PetscPrintf(comm,"Cut and paste the following into your browser:\n\n" 122 "https://www.box.com/api/oauth2/authorize?" 123 "response_type=code&" 124 "client_id=" 125 PETSC_BOX_CLIENT_ID 126 "&state=PETScState" 127 "\n\n");CHKERRQ(ierr); 128 ierr = PetscBoxStartWebServer_Private();CHKERRQ(ierr); 129 ierr = PetscStrbeginswith((const char*)result,"state=PETScState&code=",&flg);CHKERRQ(ierr); 130 if (!flg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not get expected string from Box got %s",result); 131 ierr = PetscStrncpy(buff,(const char*)result+22,sizeof(buff));CHKERRQ(ierr); 132 133 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 134 ierr = PetscHTTPSConnect("www.box.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 135 ierr = PetscStrcpy(body,"code=");CHKERRQ(ierr); 136 ierr = PetscStrcat(body,buff);CHKERRQ(ierr); 137 ierr = PetscStrcat(body,"&client_id=");CHKERRQ(ierr); 138 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ID);CHKERRQ(ierr); 139 ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr); 140 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ST);CHKERRQ(ierr); 141 ierr = PetscStrcat(body,"&grant_type=authorization_code");CHKERRQ(ierr); 142 143 ierr = PetscHTTPSRequest("POST","www.box.com/api/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 144 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 145 close(sock); 146 147 ierr = PetscPullJSONValue(buff,"access_token",access_token,tokensize,&found);CHKERRQ(ierr); 148 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return access token"); 149 ierr = PetscPullJSONValue(buff,"refresh_token",refresh_token,tokensize,&found);CHKERRQ(ierr); 150 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return refresh token"); 151 152 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); 153 ierr = PetscPrintf(comm,"programs with the option -box_refresh_token %s\n",refresh_token);CHKERRQ(ierr); 154 ierr = PetscPrintf(comm,"to access Box Drive automatically\n");CHKERRQ(ierr); 155 } 156 PetscFunctionReturn(0); 157 } 158 #endif 159 160 #undef __FUNCT__ 161 #define __FUNCT__ "PetscBoxRefresh" 162 /*@C 163 PetscBoxRefresh - Get a new authorization token for accessing Box drive from PETSc from a refresh token 164 165 Not collective, only the first process in the MPI_Comm does anything 166 167 Input Parameters: 168 + comm - MPI communicator 169 . refresh token - obtained with PetscBoxAuthorize(), if NULL PETSc will first look for one in the options data 170 if not found it will call PetscBoxAuthorize() 171 - tokensize - size of the output string access_token 172 173 Output Parameter: 174 + access_token - token that can be passed to PetscBoxUpload() 175 - 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 176 177 .seealso: PetscURLShorten(), PetscBoxAuthorize(), PetscBoxUpload() 178 179 @*/ 180 PetscErrorCode PetscBoxRefresh(MPI_Comm comm,const char refresh_token[],char access_token[],char new_refresh_token[],size_t tokensize) 181 { 182 SSL_CTX *ctx; 183 SSL *ssl; 184 int sock; 185 PetscErrorCode ierr; 186 char buff[8*1024],body[1024]; 187 PetscMPIInt rank; 188 char *refreshtoken = (char*)refresh_token; 189 PetscBool found; 190 191 PetscFunctionBegin; 192 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 193 if (!rank) { 194 if (!refresh_token) { 195 PetscBool set; 196 ierr = PetscMalloc1(512,&refreshtoken);CHKERRQ(ierr); 197 ierr = PetscOptionsGetString(NULL,"-box_refresh_token",refreshtoken,512,&set);CHKERRQ(ierr); 198 #if defined(PETSC_HAVE_SAWS) 199 if (!set) { 200 ierr = PetscBoxAuthorize(comm,access_token,new_refresh_token,512*sizeof(char));CHKERRQ(ierr); 201 ierr = PetscFree(refreshtoken);CHKERRQ(ierr); 202 PetscFunctionReturn(0); 203 } 204 #else 205 if (!set) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Must provide refresh token with -box_refresh_token XXX"); 206 #endif 207 } 208 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 209 ierr = PetscHTTPSConnect("www.box.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 210 ierr = PetscStrcpy(body,"client_id=");CHKERRQ(ierr); 211 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ID);CHKERRQ(ierr); 212 ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr); 213 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ST);CHKERRQ(ierr); 214 ierr = PetscStrcat(body,"&refresh_token=");CHKERRQ(ierr); 215 ierr = PetscStrcat(body,refreshtoken);CHKERRQ(ierr); 216 if (!refresh_token) {ierr = PetscFree(refreshtoken);CHKERRQ(ierr);} 217 ierr = PetscStrcat(body,"&grant_type=refresh_token");CHKERRQ(ierr); 218 219 ierr = PetscHTTPSRequest("POST","www.box.com/api/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 220 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 221 close(sock); 222 223 ierr = PetscPullJSONValue(buff,"access_token",access_token,tokensize,&found);CHKERRQ(ierr); 224 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return access token"); 225 ierr = PetscPullJSONValue(buff,"refresh_token",new_refresh_token,tokensize,&found);CHKERRQ(ierr); 226 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Box did not return refresh token"); 227 228 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); 229 ierr = PetscPrintf(comm,"programs with the option -box_refresh_token %s\n",new_refresh_token);CHKERRQ(ierr); 230 ierr = PetscPrintf(comm,"to access Box Drive automatically\n");CHKERRQ(ierr); 231 } 232 PetscFunctionReturn(0); 233 } 234 235 #include <sys/stat.h> 236 237 #undef __FUNCT__ 238 #define __FUNCT__ "PetscBoxUpload" 239 /*@C 240 PetscBoxUpload - Loads a file to the Box Drive 241 242 This routine has not yet been written; it is just copied from Google Drive 243 244 Not collective, only the first process in the MPI_Comm uploads the file 245 246 Input Parameters: 247 + comm - MPI communicator 248 . access_token - obtained with PetscBoxRefresh(), pass NULL to have PETSc generate one 249 - filename - file to upload; if you upload multiple times it will have different names each time on Box Drive 250 251 Options Database: 252 . -box_refresh_token XXX 253 254 Usage Patterns: 255 With PETSc option -box_refresh_token XXX given 256 PetscBoxUpload(comm,NULL,filename); will upload file with no user interaction 257 258 Without PETSc option -box_refresh_token XXX given 259 PetscBoxUpload(comm,NULL,filename); for first use will prompt user to authorize access to Box Drive with their processor 260 261 With PETSc option -box_refresh_token XXX given 262 PetscBoxRefresh(comm,NULL,access_token,sizeof(access_token)); 263 PetscBoxUpload(comm,access_token,filename); 264 265 With refresh token entered in some way by the user 266 PetscBoxRefresh(comm,refresh_token,access_token,sizeof(access_token)); 267 PetscBoxUpload(comm,access_token,filename); 268 269 PetscBoxAuthorize(comm,access_token,refresh_token,sizeof(access_token)); 270 PetscBoxUpload(comm,access_token,filename); 271 272 .seealso: PetscURLShorten(), PetscBoxAuthorize(), PetscBoxRefresh() 273 274 @*/ 275 PetscErrorCode PetscBoxUpload(MPI_Comm comm,const char access_token[],const char filename[]) 276 { 277 SSL_CTX *ctx; 278 SSL *ssl; 279 int sock; 280 PetscErrorCode ierr; 281 char head[1024],buff[8*1024],*body,*title; 282 PetscMPIInt rank; 283 struct stat sb; 284 size_t len,blen,rd; 285 FILE *fd; 286 287 PetscFunctionBegin; 288 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 289 if (!rank) { 290 ierr = PetscStrcpy(head,"Authorization: Bearer ");CHKERRQ(ierr); 291 ierr = PetscStrcat(head,access_token);CHKERRQ(ierr); 292 ierr = PetscStrcat(head,"\r\n");CHKERRQ(ierr); 293 ierr = PetscStrcat(head,"uploadType: multipart\r\n");CHKERRQ(ierr); 294 295 ierr = stat(filename,&sb); 296 if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to stat file: %s",filename); 297 len = 1024 + sb.st_size; 298 ierr = PetscMalloc1(len,&body);CHKERRQ(ierr); 299 ierr = PetscStrcpy(body,"--foo_bar_baz\r\n" 300 "Content-Type: application/json\r\n\r\n" 301 "{");CHKERRQ(ierr); 302 ierr = PetscPushJSONValue(body,"title",filename,len);CHKERRQ(ierr); 303 ierr = PetscStrcat(body,",");CHKERRQ(ierr); 304 ierr = PetscPushJSONValue(body,"mimeType","text.html",len);CHKERRQ(ierr); 305 ierr = PetscStrcat(body,",");CHKERRQ(ierr); 306 ierr = PetscPushJSONValue(body,"description","a file",len);CHKERRQ(ierr); 307 ierr = PetscStrcat(body, "}\r\n\r\n" 308 "--foo_bar_baz\r\n" 309 "Content-Type: text/html\r\n\r\n");CHKERRQ(ierr); 310 ierr = PetscStrlen(body,&blen);CHKERRQ(ierr); 311 fd = fopen (filename, "r"); 312 if (!fd) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open file: %s",filename); 313 rd = fread (body+blen, sizeof (unsigned char), sb.st_size, fd); 314 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); 315 fclose(fd); 316 body[blen + rd] = 0; 317 ierr = PetscStrcat(body,"\r\n\r\n" 318 "--foo_bar_baz\r\n"); 319 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 320 ierr = PetscHTTPSConnect("www.boxapis.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 321 ierr = PetscHTTPSRequest("POST","www.boxapis.com/upload/drive/v2/files/",head,"multipart/related; boundary=\"foo_bar_baz\"",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 322 ierr = PetscFree(body);CHKERRQ(ierr); 323 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 324 close(sock); 325 ierr = PetscStrstr(buff,"\"title\"",&title);CHKERRQ(ierr); 326 if (!title) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Upload of file %s failed",filename); 327 } 328 PetscFunctionReturn(0); 329 } 330 331 332