Socialify

Folder ..

Viewing auth.dart
102 lines (94 loc) • 3.1 KB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
import 'package:http/http.dart' as http;
import 'package:oauth2/oauth2.dart' as oauth2;
import 'package:url_launcher/url_launcher.dart';
import 'dart:io';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter/services.dart' show rootBundle;

const githubScopes = [
  'repo',
  'admin:repo_hook',
  'admin:org',
  'admin:public_key',
  'admin:org_hook',
  'gist',
  'notifications',
  'user',
  'project',
  'delete_repo',
  'admin:gpg_key',
  'workflow',
  'write:discussion',
  'write:packages',
  'read:packages',
  'delete:packages',
  'codespace'
];

final authorizationEndpoint =
    Uri.parse('https://github.com/login/oauth/authorize');
final tokenEndpoint = Uri.parse('https://github.com/login/oauth/access_token');

class _JSONAcceptingHttpClient extends http.BaseClient {
  final _httpClient = http.Client();
  @override
  Future<http.StreamedResponse> send(http.BaseRequest request) {
    request.headers['Accept'] = 'application/json';
    return _httpClient.send(request);
  }
}

// If there is no token, hide the main window and open the browser to get the token
Future<oauth2.Client> _getOAuth2Client(
    Uri redirectUri, HttpServer redirectServer) async {
  await dotenv.load(fileName: ".env");
  var grant = oauth2.AuthorizationCodeGrant(
    dotenv.env['GITHUB_CLIENT_ID']!,
    authorizationEndpoint,
    tokenEndpoint,
    secret: dotenv.env['GITHUB_CLIENT_SECRET']!,
    httpClient: _JSONAcceptingHttpClient(),
  );
  var authorizationUrl =
      grant.getAuthorizationUrl(redirectUri, scopes: githubScopes);

  await _redirect(authorizationUrl);
  var responseQueryParameters = await _listen(redirectServer);
  try {
    var client =
        await grant.handleAuthorizationResponse(responseQueryParameters);
    return client;
  } catch (e) {
    return oauth2.Client(oauth2.Credentials('null'));
  }
}

Future<void> _redirect(Uri authorizationUrl) async {
  if (await canLaunchUrl(authorizationUrl)) {
    await launchUrl(authorizationUrl);
  } else {
    throw 'Could not launch ${authorizationUrl.toString()}.';
  }
}

Future<Map<String, String>> _listen(redirectServer) async {
  var request = await redirectServer.first;
  var params = request.uri.queryParameters;
  request.response.statusCode = 200;
  request.response.headers.set('content-type', 'text/html');
  var error = params['error'];
  if (error != null) {
    // request.response.write('Error: ${params.error}');
    String failedHtml = await rootBundle.loadString('html/failed.html');
    request.response.write(failedHtml);
  } else {
    // request.response.write('Success! You can close this window now.');
    String successHtml = await rootBundle.loadString('html/success.html');
    request.response.write(successHtml);
  }
  await request.response.close();
  await redirectServer.close();
  redirectServer = null;
  return params;
}

class GithubAuth {
  static Future<oauth2.Client> getOAuth2Client() async {
    var redirectServer = await HttpServer.bind('localhost', 51691);
    var authenticatedHttpClient = await _getOAuth2Client(
        Uri.parse('http://localhost:${redirectServer.port}'), redirectServer);
    return authenticatedHttpClient;
  }
}