Gogs.pm 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package Gogs;
  2. # ABSTRACT: Subclass of Pithub
  3. use strict;
  4. use warnings;
  5. use Moo;
  6. use MIME::Base64;
  7. #use Gogs::Repos;
  8. extends 'Pithub';
  9. =head1 DESCRIPTION
  10. L<Pithub> is an acceptable API client for Gogs, since their APIs are compatible.
  11. However the two have a number of differences, so they must be accounted for.
  12. The most important of which being that all requests require an API token.
  13. =head1 METHODS
  14. =head2 get_token(%options)
  15. We can simplify tooling around this to not require you enter the "Applications" section of the gogs interface.
  16. Requires that the object is instantiated with a username,
  17. that you pass a password, and that the api_uri is secure unless you pass the 'insecure' option.
  18. If the named token exists already it will delete and re-create the named token.
  19. It is HIGHLY RECOMMENDED you delete the token at the end of your session with the delete_token() method.
  20. =cut
  21. # All API access requires a token on Gogs EXCEPT users/$user/tokens.
  22. # As such, I'm restricting every call not ending in /tokens
  23. my @TOKEN_REQUIRED_REGEXP = (qr{(?!/tokens$)});
  24. sub _validate_tok_args {
  25. my ($self,%options) = @_;
  26. die "Must instantiate with username" unless $self->user;
  27. die "Must pass token name or sha1" unless $options{name} || $options{sha1};
  28. die "Refuse to operate over insecure connections" if !$options{insecure} && _insecure($self->api_uri);
  29. die "Must provide password to fetch tokens" unless $options{password};
  30. }
  31. sub _build_tok_headers {
  32. my ($self, %options) = @_;
  33. return (
  34. 'Authorization' => "Basic ".encode_base64($self->user.":$options{password}"),
  35. 'Content-type' => "application/json",
  36. );
  37. }
  38. sub get_token {
  39. my ($self, %options) = @_;
  40. # unset the token if passed, so that we use simple auth
  41. my $tok = $self->token();
  42. $self->token("") if $tok;
  43. $self->_validate_tok_args(%options);
  44. my %auth_headers = $self->_build_tok_headers(%options);
  45. my $token_endpoint = "/users/".$self->user."/tokens";
  46. my %req = (
  47. method => 'GET',
  48. path => $token_endpoint,
  49. headers => \%auth_headers,
  50. );
  51. my $result = $self->request(%req);
  52. my $content = $result->content();
  53. die "Got bad response from server" unless ref $content eq "ARRAY";
  54. my $token_actual;
  55. foreach my $token (@$content) {
  56. # If it exists, we have no means of deleteing it unless we actually have the real SHA1 (the one in list is not real).
  57. # As such just die.
  58. die "Token with name $options{name} already exists, cannot continue. Please delete it manually." if $token->{name} eq $options{name};
  59. }
  60. # No such token named, so let's just make one.
  61. $req{method} = 'POST';
  62. $req{data} = qq|{ "name":"$options{name}" }|;
  63. $result = $self->request(%req);
  64. $content = $result->content();
  65. # Set the token again, since we are done with the requests
  66. $self->token($tok) if $tok;
  67. die "Got bad response from server" unless ref $content eq "HASH";
  68. return $content->{sha1};
  69. }
  70. =head2 delete_token(%options)
  71. Delete the token identified by the provided sha1 in %options.
  72. Should return a token name.
  73. Dies when unsuccessful.
  74. =cut
  75. sub delete_token {
  76. my ($self, %options) = @_;
  77. # unset the token if passed, so that we use simple auth
  78. my $tok = $self->token();
  79. $self->token("") if $tok;
  80. $self->_validate_tok_args(%options);
  81. my %auth_headers = $self->_build_tok_headers(%options);
  82. my %req = (
  83. method => 'DELETE',
  84. path => "/users/".$self->user."/tokens",
  85. headers => \%auth_headers,
  86. );
  87. $req{data} = qq|{ "sha1":"$options{sha1}" }|;
  88. my $result = $self->request(%req);
  89. # Set the token again, since we are done with the requests
  90. $self->token($tok) if $tok;
  91. die "Got bad response from server on DELETE of token" unless $result && $result->response->is_success;
  92. return $result;
  93. }
  94. sub _insecure {
  95. my $uri = shift;
  96. return $uri =~ m/^http:\/\//;
  97. }
  98. 1;