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